String
Java'da iki diziyi birleştirmem gerekiyor .
void f(String[] first, String[] second) {
String[] both = ???
}
Bunu yapmanın en kolay yolu nedir?
array1 + array2
birleşim elde etmediğini merak ediyor .
String
Java'da iki diziyi birleştirmem gerekiyor .
void f(String[] first, String[] second) {
String[] both = ???
}
Bunu yapmanın en kolay yolu nedir?
array1 + array2
birleşim elde etmediğini merak ediyor .
Yanıtlar:
Eski Apache Commons Lang kütüphanesinden tek satırlık bir çözüm buldum.
ArrayUtils.addAll(T[], T...)
Kod:
String[] both = ArrayUtils.addAll(first, second);
İki diziyi birleştirecek ve sonucu döndürecek basit bir yöntem:
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;
}
İlkel veri türleriyle değil, yalnızca nesne türleriyle çalışmayacağını unutmayın.
Aşağıdaki biraz daha karmaşık sürüm hem nesne hem de ilkel dizilerle çalışır. Bu kullanarak gerçekleştirir T
yerine T[]
argüman türü olarak.
Ayrıca, sonucun bileşen türü olarak en genel türü seçerek iki farklı türden dizileri birleştirmeyi de mümkün kılar.
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;
}
İşte bir örnek:
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);
. Daha önce hiç görmedim. @beaudet Bence bu açıklama, neden bastırıldığını düşünüyor.
İstediğiniz sayıda diziyi birleştirmek için genişletilebilecek tamamen genel bir sürüm yazmak mümkündür. Bu sürümler kullandıkları için Java 6 gerektirirArrays.copyOf()
Her iki sürüm de ara List
nesneler oluşturmaktan kaçınır ve System.arraycopy()
büyük dizileri kopyalamanın mümkün olduğunca hızlı olmasını sağlamak için kullanılır.
İki dizide şöyle görünür:
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;
}
Ve rastgele sayıda dizi için (> = 1) şöyle görünür:
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
ile byte
(ve kaybetmek <T>
).
ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
concat(ai, ad)
, nerede ai
olduğunu Integer[]
ve ad
bir Double[]
. (Bu durumda, type parametresi derleyici tarafından <T>
çözümlenir <? extends Number>
.) Tarafından oluşturulan Arrays.copyOf
dizi, ilk dizinin bileşen türüne (yani Integer
bu örnekte) sahip olacaktır. İşlev ikinci diziyi kopyalamak üzereyken, bir ArrayStoreException
atılır. Çözüm, ek bir Class<T> type
parametreye sahip olmaktır .
Stream
Java 8'de kullanma :
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);
Ya da şunu kullanarak flatMap
:
String[] both = Stream.of(a, b).flatMap(Stream::of)
.toArray(String[]::new);
Bunu genel bir tür için yapmak için yansıma kullanmanız gerekir:
@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));
.boxed()
türden Stream
ziyade türden IntStream
olması gerekir Stream.concat
.
a
ve b
vardır int[]
, kullanımıint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
System.arrayCopy
. Ama özellikle yavaş değil. Muhtemelen bunu yapmak zorunda çok sahip birçok kez büyük diziler gerçekten maddeye yürütme zamanı farkı performans duyarlı bağlamlarda.
Veya sevgili Guava ile :
String[] both = ObjectArrays.concat(first, second, String.class);
Ayrıca, ilkel diziler için sürümler vardır:
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)
İki diziyi iki kod satırına ekleyebilirsiniz.
String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);
Bu hızlı ve verimli bir çözümdür ve ilkel tipler için işe yarayacak ve ilgili iki yöntem aşırı yüklenecektir.
ArrayLists, stream, vb. İçeren çözümlerden kaçınmalısınız, çünkü bunların faydalı bir amaç için geçici bellek ayırması gerekir.
for
Verimli olmadığı için büyük diziler için döngülerden kaçınmalısınız . Yerleşik yöntemler son derece hızlı olan blok kopyalama işlevlerini kullanır.
Java API'sini kullanma:
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])
daha hızlı olacak both.toArray(new String[both.size()])
bizim naif sezgi çelişse bile. Bu nedenle optimizasyon sırasında gerçek performansı ölçmek çok önemlidir. Veya daha karmaşık varyantın avantajı kanıtlanamadığında daha basit yapıyı kullanın.
% 100 eski java ve içermeyen bir çözüm System.arraycopy
(örneğin GWT istemcisinde mevcut değildir):
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
Çek eklemek isteyebilirsiniz . Ve belki de bazı değişkenlerinizi olarak ayarlayın final
.
null
kontrolleri, NPE'leri göstermek yerine gizleyecek ve yerel değişkenler için final kullanmanın herhangi bir faydası yok (henüz).
Son zamanlarda aşırı bellek döndürme ile ilgili sorunlar yaşadım. A ve / veya b'nin yaygın olarak boş olduğu biliniyorsa, burada silvertab kodunun başka bir uyarlaması da vardır (ayrıca üretilmiştir):
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;
}
Düzenleme: Bu yazının önceki bir sürümü, bunun gibi dizi yeniden kullanımının açıkça belgeleneceğini belirtti. Maarten yorumlarda belirtildiği gibi, genel olarak if ifadelerini kaldırmak daha iyi olur, böylece belgelere sahip olma ihtiyacını ortadan kaldırır. Ama yine de, eğer if ifadeleri ilk başta bu özel optimizasyonun bütün noktasıydı. Bu cevabı burada bırakacağım ama dikkatli ol!
System.arraycopy
dizinin içeriğini kopya düşündüm ?
if
ifadeyi dışarıda bırakmak en kolay çözüm olacaktır.
Fonksiyonel Java kütüphanesi birleştirme gibi kullanışlı yöntemlerle diziler donatır bir dizi sarıcı sınıfı vardır.
import static fj.data.Array.array;
...ve sonra
Array<String> both = array(first).append(array(second));
Açılmamış diziyi geri almak için arayın
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()])
:;)
İşte silvertab'ın çözümünün, jenerikler sonradan uyarlanmış bir uyarlaması:
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;
}
NOT: Java 6 çözümü için Joachim'in cevabına bakın . Sadece uyarıyı ortadan kaldırmaz; ayrıca daha kısa, daha verimli ve okunması daha kolay!
Bu şekilde kullanırsanız, herhangi bir üçüncü taraf sınıfını içe aktarmanıza gerek yoktur.
Birleştirmek istiyorsanız String
Eşdeğer iki Dize Dizisi için örnek kod
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;
}
Birleştirmek istiyorsanız Int
Eşdeğer iki Tamsayı Dizisi için örnek kod
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;
}
İşte Ana yöntem
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));
}
}
Bu şekilde de kullanabiliriz.
Lütfen zaten uzun olan bu listeye başka bir sürüm daha eklediğiniz için beni affedin. Her cevaba baktım ve imzada sadece bir parametreli bir versiyon istediğime karar verdim. Ayrıca beklenmedik bir girdi olması durumunda mantıklı bilgi ile erken başarısızlıktan yararlanmak için bazı argüman kontrolü ekledim.
@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;
}
Bunu bir Arraylist'e dönüştürmeyi deneyebilir ve addAll yöntemini kullanarak bir diziye geri dönüştürebilirsiniz.
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
Burada silvertab tarafından yazılan sözde kod çözümünün çalışma kodunda olası bir uygulama.
Teşekkürler 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;
}
}
Sırada builder arayüzü var.
Not: Bir inşaatçı gereklidir, çünkü java'da yapmak mümkün değildir
new T[size]
genel tip silme nedeniyle:
public interface ArrayBuilderI<T> {
public T[] build(int size);
}
Burada, bir Integer
dizi oluşturan arayüzü uygulayan somut bir üretici :
public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {
@Override
public Integer[] build(int size) {
return new Integer[size];
}
}
Ve son olarak uygulama / test:
@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]);
}
}
Vaov! dış bağımlılıklara bağlı bazı basit cevaplar da dahil olmak üzere birçok karmaşık cevap burada. böyle yapmaya ne dersin:
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]);
Bu işe yarar, ancak kendi hata denetiminizi eklemeniz gerekir.
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();
}
}
Muhtemelen en verimli değildir, ancak Java'nın kendi API'sından başka bir şeye güvenmez.
for
döngüyü bununla değiştirmek daha iyi olurdu :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)
İlk for
döngüyü atlamak için kullanın . Boyutuyla orantılı zaman kazandırır arr1
.
Bu, bir String dizisi için dönüştürülmüş bir işlevdir:
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;
}
Basitçe
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());
}
}
Ve sadece yap Array.concat(arr1, arr2)
. arr1
Ve arr2
aynı türde olduğu sürece , bu size her iki diziyi içeren aynı türde başka bir dizi verecektir.
@SuppressWarnings ek açıklamasına gerek duymadan yüksek performanslı System.arraycopy kullanan genel bir statik sürüm:
public static <T> T[] arrayConcat(T[] a, T[] b) {
T[] both = Arrays.copyOf(a, a.length + b.length);
System.arraycopy(b, 0, both, a.length, b.length);
return both;
}
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;
}
İşte Joachim Sauer'ın concatAll'ın biraz geliştirilmiş sürümü. Java 6 veya System.arraycopy kullanarak çalışma zamanında varsa Java 5 veya 6 üzerinde çalışabilir. Bu yöntem (IMHO) Android için mükemmeldir, çünkü Android <9'da (System.arraycopy içermeyen) çalışır, ancak mümkünse daha hızlı yöntemi kullanır.
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;
}
Soru hakkında düşünmenin başka bir yolu. İki veya daha fazla diziyi birleştirmek için tek yapmanız gereken her dizinin tüm öğelerini listelemek ve sonra yeni bir dizi oluşturmaktır. Bu bir a oluşturmak gibi geliyor List<T>
ve sonra çağırır toArray
. Diğer bazı cevaplar kullanır ArrayList
ve bu iyi. Peki ya kendimizi uygulamaya ne dersiniz? Zor değil:
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);
}
Yukarıdakilerin, kullanılan çözümlere eşdeğer olduğuna inanıyorum System.arraycopy
. Ancak bunun kendi güzelliği olduğunu düşünüyorum.
Nasıl olur:
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()]);
}
Birden fazla dizinin birleştirilmesine izin veren basit bir varyasyon:
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()]);
}
Yalnızca Javas kendi API'sını kullanma:
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]);
}
Şimdi, bu kod en verimli değildir, ancak sadece standart java sınıflarına dayanır ve anlaşılması kolaydır. Herhangi bir sayıda String [] (sıfır dizi bile) için çalışır.