Saya perlu menggabungkan dua String
array di Jawa.
void f(String[] first, String[] second) {
String[] both = ???
}
Apa cara termudah untuk melakukan ini?
array1 + array2
rangkaian sederhana .
Saya perlu menggabungkan dua String
array di Jawa.
void f(String[] first, String[] second) {
String[] both = ???
}
Apa cara termudah untuk melakukan ini?
array1 + array2
rangkaian sederhana .
Jawaban:
Saya menemukan solusi satu baris dari perpustakaan lama Apache Commons Lang yang bagus.
ArrayUtils.addAll(T[], T...)
Kode:
String[] both = ArrayUtils.addAll(first, second);
Berikut adalah metode sederhana yang akan menggabungkan dua array dan mengembalikan hasilnya:
public <T> T[] concatenate(T[] a, T[] b) {
int aLen = a.length;
int bLen = b.length;
@SuppressWarnings("unchecked")
T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
Perhatikan bahwa itu tidak akan berfungsi dengan tipe data primitif, hanya dengan tipe objek.
Versi yang sedikit lebih rumit berikut ini berfungsi dengan array objek dan primitif. Itu melakukan ini dengan menggunakan T
bukan T[]
sebagai tipe argumen.
Hal ini juga memungkinkan untuk menggabungkan array dari dua tipe yang berbeda dengan memilih tipe yang paling umum sebagai tipe komponen dari hasilnya.
public static <T> T concatenate(T a, T b) {
if (!a.getClass().isArray() || !b.getClass().isArray()) {
throw new IllegalArgumentException();
}
Class<?> resCompType;
Class<?> aCompType = a.getClass().getComponentType();
Class<?> bCompType = b.getClass().getComponentType();
if (aCompType.isAssignableFrom(bCompType)) {
resCompType = aCompType;
} else if (bCompType.isAssignableFrom(aCompType)) {
resCompType = bCompType;
} else {
throw new IllegalArgumentException();
}
int aLen = Array.getLength(a);
int bLen = Array.getLength(b);
@SuppressWarnings("unchecked")
T result = (T) Array.newInstance(resCompType, aLen + bLen);
System.arraycopy(a, 0, result, 0, aLen);
System.arraycopy(b, 0, result, aLen, bLen);
return result;
}
Berikut ini sebuah contoh:
Assert.assertArrayEquals(new int[] { 1, 2, 3 }, concatenate(new int[] { 1, 2 }, new int[] { 3 }));
Assert.assertArrayEquals(new Number[] { 1, 2, 3f }, concatenate(new Integer[] { 1, 2 }, new Number[] { 3f }));
Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
. Secara mengejutkan saya belum pernah melihat itu sebelumnya. @beaudet Saya pikir penjelasannya baik-baik saja di sini, mengingat mengapa ini sedang ditekan.
Dimungkinkan untuk menulis versi sepenuhnya generik yang bahkan dapat diperluas untuk menggabungkan sejumlah array. Versi ini membutuhkan Java 6, seperti yang mereka gunakanArrays.copyOf()
Kedua versi menghindari membuat List
objek perantara dan menggunakan System.arraycopy()
untuk memastikan bahwa menyalin array besar secepat mungkin.
Untuk dua array terlihat seperti ini:
public static <T> T[] concat(T[] first, T[] second) {
T[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
Dan untuk jumlah array yang arbitrer (> = 1) terlihat seperti ini:
public static <T> T[] concatAll(T[] first, T[]... rest) {
int totalLength = first.length;
for (T[] array : rest) {
totalLength += array.length;
}
T[] result = Arrays.copyOf(first, totalLength);
int offset = first.length;
for (T[] array : rest) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
return result;
}
T
- masing dengan byte
(dan kehilangan <T>
).
ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
concat(ai, ad)
, di mana ai
ada Integer[]
dan ad
sekarang Double[]
. (Dalam hal ini, parameter tipe <T>
dipecahkan <? extends Number>
oleh kompiler.) Array yang dibuat oleh Arrays.copyOf
akan memiliki tipe komponen array pertama, yaitu Integer
dalam contoh ini. Ketika fungsi akan menyalin array kedua, sebuah ArrayStoreException
akan dilempar. Solusinya adalah memiliki Class<T> type
parameter tambahan .
Menggunakan Stream
di Java 8:
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);
Atau seperti ini, menggunakan flatMap
:
String[] both = Stream.of(a, b).flatMap(Stream::of)
.toArray(String[]::new);
Untuk melakukan ini untuk tipe generik Anda harus menggunakan refleksi:
@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));
.boxed()
mereka yang Stream
bukan tipe misalnya IntStream
yang tidak dapat diteruskan sebagai parameter Stream.concat
.
a
dan b
adalah int[]
, penggunaanint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
System.arrayCopy
. Tapi tidak terlalu lambat juga. Anda mungkin harus melakukan ini sangat berkali-kali dengan besar array di benar-benar kinerja konteks sensitif untuk waktu eksekusi perbedaan untuk peduli.
Atau dengan Jambu kesayangan :
String[] both = ObjectArrays.concat(first, second, String.class);
Juga, ada versi untuk array primitif:
Booleans.concat(first, second)
Bytes.concat(first, second)
Chars.concat(first, second)
Doubles.concat(first, second)
Shorts.concat(first, second)
Ints.concat(first, second)
Longs.concat(first, second)
Floats.concat(first, second)
Anda dapat menambahkan dua array dalam dua baris kode.
String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);
Ini adalah solusi cepat dan efisien dan akan bekerja untuk tipe primitif serta dua metode yang terlibat kelebihan beban.
Anda harus menghindari solusi yang melibatkan ArrayLists, stream, dll karena ini akan perlu mengalokasikan memori sementara tanpa tujuan yang bermanfaat.
Anda harus menghindari for
loop untuk array besar karena ini tidak efisien. Metode bawaan menggunakan fungsi blok-salin yang sangat cepat.
Menggunakan Java API:
String[] f(String[] first, String[] second) {
List<String> both = new ArrayList<String>(first.length + second.length);
Collections.addAll(both, first);
Collections.addAll(both, second);
return both.toArray(new String[both.size()]);
}
both.toArray(new String[0])
akan lebih cepat daripada both.toArray(new String[both.size()])
, bahkan jika itu bertentangan dengan intuisi naif kita. Itulah mengapa sangat penting untuk mengukur kinerja aktual saat mengoptimalkan. Atau cukup gunakan konstruk yang lebih sederhana, ketika keunggulan varian yang lebih rumit tidak dapat dibuktikan.
Solusi 100% java lama dan tanpa System.arraycopy
(tidak tersedia di klien GWT misalnya):
static String[] concat(String[]... arrays) {
int length = 0;
for (String[] array : arrays) {
length += array.length;
}
String[] result = new String[length];
int pos = 0;
for (String[] array : arrays) {
for (String element : array) {
result[pos] = element;
pos++;
}
}
return result;
}
null
cek. Dan mungkin mengatur beberapa variabel Anda final
.
null
Pemeriksaan @TrippKinetics akan menyembunyikan NPE daripada menunjukkannya dan menggunakan final untuk vars lokal tidak memiliki manfaat (belum).
Saya baru-baru ini menghadapi masalah dengan rotasi memori yang berlebihan. Jika a dan / atau b diketahui umumnya kosong, berikut ini adalah adaptasi lain dari kode silvertab (dibuat juga):
private static <T> T[] concatOrReturnSame(T[] a, T[] b) {
final int alen = a.length;
final int blen = b.length;
if (alen == 0) {
return b;
}
if (blen == 0) {
return a;
}
final T[] result = (T[]) java.lang.reflect.Array.
newInstance(a.getClass().getComponentType(), alen + blen);
System.arraycopy(a, 0, result, 0, alen);
System.arraycopy(b, 0, result, alen, blen);
return result;
}
Sunting: Versi sebelumnya dari posting ini menyatakan bahwa penggunaan ulang array seperti ini harus didokumentasikan dengan jelas. Seperti yang ditunjukkan oleh Maarten dalam komentar, secara umum akan lebih baik untuk menghapus pernyataan if, sehingga membatalkan kebutuhan untuk memiliki dokumentasi. Tetapi sekali lagi, pernyataan if adalah inti dari optimasi khusus ini. Saya akan meninggalkan jawaban ini di sini, tetapi berhati-hatilah!
System.arraycopy
menyalin isi array?
if
pernyataan saja merupakan cara yang paling mudah.
The Java Fungsional perpustakaan memiliki kelas wrapper array melengkapi array dengan metode berguna seperti Rangkaian.
import static fj.data.Array.array;
...lalu
Array<String> both = array(first).append(array(second));
Untuk mendapatkan kembali array yang terbuka, panggil
String[] s = both.array();
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));
both.toArray(new String[0]);
both.toArray(new String[both.size()])
Berikut ini adalah adaptasi dari solusi silvertab, dengan obat generik yang dilengkapi:
static <T> T[] concat(T[] a, T[] b) {
final int alen = a.length;
final int blen = b.length;
final T[] result = (T[]) java.lang.reflect.Array.
newInstance(a.getClass().getComponentType(), alen + blen);
System.arraycopy(a, 0, result, 0, alen);
System.arraycopy(b, 0, result, alen, blen);
return result;
}
CATATAN: Lihat jawaban Joachim untuk solusi Java 6. Tidak hanya menghilangkan peringatan; juga lebih pendek, lebih efisien, dan lebih mudah dibaca!
Jika Anda menggunakan cara ini maka Anda tidak perlu mengimpor kelas pihak ketiga mana pun.
Jika Anda ingin menyatukan String
Kode sampel untuk dua String Array
public static String[] combineString(String[] first, String[] second){
int length = first.length + second.length;
String[] result = new String[length];
System.arraycopy(first, 0, result, 0, first.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
Jika Anda ingin menyatukan Int
Kode sampel untuk dua bilangan bulat Integer
public static int[] combineInt(int[] a, int[] b){
int length = a.length + b.length;
int[] result = new int[length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
Berikut adalah metode Utama
public static void main(String[] args) {
String [] first = {"a", "b", "c"};
String [] second = {"d", "e"};
String [] joined = combineString(first, second);
System.out.println("concatenated String array : " + Arrays.toString(joined));
int[] array1 = {101,102,103,104};
int[] array2 = {105,106,107,108};
int[] concatenateInt = combineInt(array1, array2);
System.out.println("concatenated Int array : " + Arrays.toString(concatenateInt));
}
}
Kita bisa menggunakan cara ini juga.
Maafkan saya karena telah menambahkan versi lain ke daftar yang sudah lama ini. Saya melihat setiap jawaban dan memutuskan bahwa saya benar-benar menginginkan versi dengan hanya satu parameter di tanda tangan. Saya juga menambahkan beberapa pemeriksaan argumen untuk mendapatkan manfaat dari kegagalan awal dengan info yang masuk akal jika input tidak terduga.
@SuppressWarnings("unchecked")
public static <T> T[] concat(T[]... inputArrays) {
if(inputArrays.length < 2) {
throw new IllegalArgumentException("inputArrays must contain at least 2 arrays");
}
for(int i = 0; i < inputArrays.length; i++) {
if(inputArrays[i] == null) {
throw new IllegalArgumentException("inputArrays[" + i + "] is null");
}
}
int totalLength = 0;
for(T[] array : inputArrays) {
totalLength += array.length;
}
T[] result = (T[]) Array.newInstance(inputArrays[0].getClass().getComponentType(), totalLength);
int offset = 0;
for(T[] array : inputArrays) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
return result;
}
Anda dapat mencoba mengubahnya menjadi Arraylist dan menggunakan metode addAll kemudian mengonversi kembali ke array.
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
Di sini kemungkinan implementasi dalam kode kerja dari solusi kode semu yang ditulis oleh silvertab.
Terima kasih silvertab!
public class Array {
public static <T> T[] concat(T[] a, T[] b, ArrayBuilderI<T> builder) {
T[] c = builder.build(a.length + b.length);
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
}
Mengikuti selanjutnya adalah antarmuka pembangun.
Catatan: Builder diperlukan karena di java tidak mungkin dilakukan
new T[size]
karena penghapusan tipe generik:
public interface ArrayBuilderI<T> {
public T[] build(int size);
}
Di sini pembangun beton mengimplementasikan antarmuka, membangun sebuah Integer
array:
public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {
@Override
public Integer[] build(int size) {
return new Integer[size];
}
}
Dan akhirnya aplikasi / tes:
@Test
public class ArrayTest {
public void array_concatenation() {
Integer a[] = new Integer[]{0,1};
Integer b[] = new Integer[]{2,3};
Integer c[] = Array.concat(a, b, new IntegerArrayBuilder());
assertEquals(4, c.length);
assertEquals(0, (int)c[0]);
assertEquals(1, (int)c[1]);
assertEquals(2, (int)c[2]);
assertEquals(3, (int)c[3]);
}
}
Wow! banyak jawaban kompleks di sini termasuk beberapa jawaban sederhana yang bergantung pada dependensi eksternal. bagaimana kalau melakukannya seperti ini:
String [] arg1 = new String{"a","b","c"};
String [] arg2 = new String{"x","y","z"};
ArrayList<String> temp = new ArrayList<String>();
temp.addAll(Arrays.asList(arg1));
temp.addAll(Arrays.asList(arg2));
String [] concatedArgs = temp.toArray(new String[arg1.length+arg2.length]);
Ini berfungsi, tetapi Anda harus memasukkan pemeriksaan kesalahan Anda sendiri.
public class StringConcatenate {
public static void main(String[] args){
// Create two arrays to concatenate and one array to hold both
String[] arr1 = new String[]{"s","t","r","i","n","g"};
String[] arr2 = new String[]{"s","t","r","i","n","g"};
String[] arrBoth = new String[arr1.length+arr2.length];
// Copy elements from first array into first part of new array
for(int i = 0; i < arr1.length; i++){
arrBoth[i] = arr1[i];
}
// Copy elements from second array into last part of new array
for(int j = arr1.length;j < arrBoth.length;j++){
arrBoth[j] = arr2[j-arr1.length];
}
// Print result
for(int k = 0; k < arrBoth.length; k++){
System.out.print(arrBoth[k]);
}
// Additional line to make your terminal look better at completion!
System.out.println();
}
}
Ini mungkin bukan yang paling efisien, tetapi tidak bergantung pada apa pun selain API Java sendiri.
for
loop kedua dengan itu:for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)
untuk melewati for
loop pertama . Menghemat waktu sebanding dengan ukuran arr1
.
Ini adalah fungsi yang dikonversi untuk array String:
public String[] mergeArrays(String[] mainArray, String[] addArray) {
String[] finalArray = new String[mainArray.length + addArray.length];
System.arraycopy(mainArray, 0, finalArray, 0, mainArray.length);
System.arraycopy(addArray, 0, finalArray, mainArray.length, addArray.length);
return finalArray;
}
Bagaimana dengan sederhana
public static class Array {
public static <T> T[] concat(T[]... arrays) {
ArrayList<T> al = new ArrayList<T>();
for (T[] one : arrays)
Collections.addAll(al, one);
return (T[]) al.toArray(arrays[0].clone());
}
}
Dan lakukan saja Array.concat(arr1, arr2)
. Selama arr1
dan arr2
dari jenis yang sama, ini akan memberi Anda array lain dari jenis yang sama yang mengandung kedua array.
public String[] concat(String[]... arrays)
{
int length = 0;
for (String[] array : arrays) {
length += array.length;
}
String[] result = new String[length];
int destPos = 0;
for (String[] array : arrays) {
System.arraycopy(array, 0, result, destPos, array.length);
destPos += array.length;
}
return result;
}
Ini adalah versi saya yang sedikit lebih baik dari concatAll Joachim Sauer. Ini dapat bekerja pada Java 5 atau 6, menggunakan System.arraycopy Java 6 jika tersedia saat runtime. Metode ini (IMHO) sangat cocok untuk Android, karena bekerja pada Android <9 (yang tidak memiliki System.arraycopy) tetapi akan menggunakan metode yang lebih cepat jika memungkinkan.
public static <T> T[] concatAll(T[] first, T[]... rest) {
int totalLength = first.length;
for (T[] array : rest) {
totalLength += array.length;
}
T[] result;
try {
Method arraysCopyOf = Arrays.class.getMethod("copyOf", Object[].class, int.class);
result = (T[]) arraysCopyOf.invoke(null, first, totalLength);
} catch (Exception e){
//Java 6 / Android >= 9 way didn't work, so use the "traditional" approach
result = (T[]) java.lang.reflect.Array.newInstance(first.getClass().getComponentType(), totalLength);
System.arraycopy(first, 0, result, 0, first.length);
}
int offset = first.length;
for (T[] array : rest) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
return result;
}
Cara lain untuk memikirkan pertanyaan itu. Untuk menggabungkan dua array atau lebih, yang harus dilakukan adalah membuat daftar semua elemen dari setiap array, dan kemudian membangun array baru. Ini terdengar seperti membuat List<T>
dan kemudian memanggilnya toArray
. Beberapa jawaban lain digunakan ArrayList
, dan itu tidak masalah. Tetapi bagaimana dengan mengimplementasikan kita sendiri? Itu tidak sulit:
private static <T> T[] addAll(final T[] f, final T...o){
return new AbstractList<T>(){
@Override
public T get(int i) {
return i>=f.length ? o[i - f.length] : f[i];
}
@Override
public int size() {
return f.length + o.length;
}
}.toArray(f);
}
Saya percaya hal di atas setara dengan solusi yang digunakan System.arraycopy
. Namun saya pikir yang ini memiliki keindahannya sendiri.
Bagaimana tentang :
public String[] combineArray (String[] ... strings) {
List<String> tmpList = new ArrayList<String>();
for (int i = 0; i < strings.length; i++)
tmpList.addAll(Arrays.asList(strings[i]));
return tmpList.toArray(new String[tmpList.size()]);
}
Variasi sederhana yang memungkinkan penggabungan lebih dari satu array:
public static String[] join(String[]...arrays) {
final List<String> output = new ArrayList<String>();
for(String[] array : arrays) {
output.addAll(Arrays.asList(array));
}
return output.toArray(new String[output.size()]);
}
Hanya menggunakan API milik Javas:
String[] join(String[]... arrays) {
// calculate size of target array
int size = 0;
for (String[] array : arrays) {
size += array.length;
}
// create list of appropriate size
java.util.List list = new java.util.ArrayList(size);
// add arrays
for (String[] array : arrays) {
list.addAll(java.util.Arrays.asList(array));
}
// create and return final array
return list.toArray(new String[size]);
}
Sekarang, kode ini bukan yang paling efisien, tetapi hanya bergantung pada kelas-kelas java standar dan mudah dimengerti. Ini berfungsi untuk sejumlah String [] (bahkan nol array).