Ich muss zwei String
Arrays in Java verketten .
void f(String[] first, String[] second) {
String[] both = ???
}
Was ist der einfachste Weg, dies zu tun?
array1 + array2
Verkettung erhalten hat.
Ich muss zwei String
Arrays in Java verketten .
void f(String[] first, String[] second) {
String[] both = ???
}
Was ist der einfachste Weg, dies zu tun?
array1 + array2
Verkettung erhalten hat.
Antworten:
Ich habe eine einzeilige Lösung aus der guten alten Apache Commons Lang-Bibliothek gefunden.
ArrayUtils.addAll(T[], T...)
Code:
String[] both = ArrayUtils.addAll(first, second);
Hier ist eine einfache Methode, die zwei Arrays verkettet und das Ergebnis zurückgibt:
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;
}
Beachten Sie, dass dies nicht mit primitiven Datentypen funktioniert, sondern nur mit Objekttypen.
Die folgende etwas kompliziertere Version funktioniert sowohl mit Objekt- als auch mit primitiven Arrays. Dies geschieht durch Verwendung von T
anstelle von T[]
als Argumenttyp.
Es ist auch möglich, Arrays von zwei verschiedenen Typen zu verketten, indem der allgemeinste Typ als Komponententyp des Ergebnisses ausgewählt wird.
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;
}
Hier ist ein Beispiel:
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);
. Ich habe das überraschenderweise noch nie gesehen. @beaudet Ich denke, die Anmerkung ist hier in Ordnung, wenn man bedenkt, warum sie unterdrückt wird.
Es ist möglich, eine vollständig generische Version zu schreiben, die sogar erweitert werden kann, um eine beliebige Anzahl von Arrays zu verketten. Diese Versionen erfordern Java 6, wie sie verwendenArrays.copyOf()
Beide Versionen vermeiden das Erstellen von Zwischenobjekten List
und stellen System.arraycopy()
sicher, dass das Kopieren großer Arrays so schnell wie möglich erfolgt.
Für zwei Arrays sieht es so aus:
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;
}
Und für eine beliebige Anzahl von Arrays (> = 1) sieht es so aus:
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
durch byte
(und verlieren Sie den <T>
).
ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
concat(ai, ad)
wo ai
ist Integer[]
und ad
ist Double[]
. (In diesem Fall wird die Typ - Parameter <T>
werden gelöst <? extends Number>
durch den Compiler.) Das Array erstellt von Arrays.copyOf
dem Komponententyp des ersten Arrays, dh Integer
in diesem Beispiel. Wenn die Funktion das zweite Array kopieren ArrayStoreException
will , wird ein ausgelöst. Die Lösung besteht darin, einen zusätzlichen Class<T> type
Parameter zu haben .
Verwenden Stream
in Java 8:
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);
Oder so mit flatMap
:
String[] both = Stream.of(a, b).flatMap(Stream::of)
.toArray(String[]::new);
Um dies für einen generischen Typ zu tun, müssen Sie Reflection verwenden:
@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));
.boxed()
dass sie vom Typ sind Stream
und nicht z. B., IntStream
die nicht als Parameter an übergeben werden können Stream.concat
.
a
und b
sind int[]
, verwenden Sieint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
System.arrayCopy
. Aber auch nicht besonders langsam. Sie müssen dies wahrscheinlich sehr oft mit riesigen Arrays in wirklich leistungsempfindlichen Kontexten tun, damit der Unterschied in der Ausführungszeit eine Rolle spielt.
Oder mit der geliebten Guave :
String[] both = ObjectArrays.concat(first, second, String.class);
Es gibt auch Versionen für primitive Arrays:
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)
Sie können die beiden Arrays in zwei Codezeilen anhängen.
String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);
Dies ist eine schnelle und effiziente Lösung und funktioniert sowohl für primitive Typen als auch für die beiden beteiligten Methoden.
Sie sollten Lösungen mit ArrayLists, Streams usw. vermeiden, da diese temporären Speicher ohne nützlichen Zweck zuweisen müssen.
Sie sollten for
Schleifen für große Arrays vermeiden, da diese nicht effizient sind. Die integrierten Methoden verwenden Blockkopierfunktionen, die extrem schnell sind.
Verwenden der 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])
schneller als both.toArray(new String[both.size()])
, auch wenn dies unserer naiven Intuition widerspricht. Deshalb ist es so wichtig, die tatsächliche Leistung bei der Optimierung zu messen. Oder verwenden Sie einfach das einfachere Konstrukt, wenn der Vorteil der komplizierteren Variante nicht nachgewiesen werden kann.
Eine Lösung aus 100% altem Java und ohne System.arraycopy
(zum Beispiel im GWT-Client nicht verfügbar):
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
Schecks hinzufügen . Und vielleicht setzen Sie einige Ihrer Variablen auf final
.
null
Überprüfungen würden NPEs verbergen, anstatt sie anzuzeigen , und die Verwendung von final für lokale Variablen hat (noch) keinen Vorteil.
Ich habe kürzlich Probleme mit übermäßiger Speicherrotation bekämpft. Wenn bekannt ist, dass a und / oder b häufig leer sind, finden Sie hier eine weitere Anpassung des silvertab-Codes (ebenfalls generiert):
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;
}
Bearbeiten: In einer früheren Version dieses Beitrags wurde angegeben, dass eine solche Wiederverwendung von Arrays klar dokumentiert werden muss. Wie Maarten in den Kommentaren ausführt, ist es im Allgemeinen besser, nur die if-Anweisungen zu entfernen, wodurch die Notwendigkeit einer Dokumentation entfällt. Andererseits waren diese if-Aussagen in erster Linie der springende Punkt dieser speziellen Optimierung. Ich werde diese Antwort hier lassen, aber seien Sie vorsichtig!
System.arraycopy
kopiert den Inhalt des Arrays?
if
Aussagen wegzulassen, wäre die einfachste Lösung.
Die Functional Java- Bibliothek verfügt über eine Array-Wrapper-Klasse, die Arrays mit praktischen Methoden wie Verkettung ausstattet.
import static fj.data.Array.array;
...und dann
Array<String> both = array(first).append(array(second));
Rufen Sie an, um das ausgepackte Array wieder herauszuholen
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()])
;)
Hier ist eine Anpassung der Lösung von silvertab mit nachgerüsteten Generika:
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;
}
HINWEIS: Siehe Joachims Antwort für eine Java 6-Lösung. Es beseitigt nicht nur die Warnung; es ist auch kürzer, effizienter und leichter zu lesen!
Wenn Sie diese Methode verwenden, müssen Sie keine Klasse von Drittanbietern importieren.
Wenn Sie verketten möchten String
Beispielcode für Concate Two 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;
}
Wenn Sie verketten möchten Int
Beispielcode für zwei ganzzahlige Ganzzahl-Arrays
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;
}
Hier ist die Hauptmethode
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));
}
}
Wir können diesen Weg auch benutzen.
Bitte verzeihen Sie mir, dass ich dieser bereits langen Liste noch eine weitere Version hinzugefügt habe. Ich sah mir jede Antwort an und entschied, dass ich wirklich eine Version mit nur einem Parameter in der Signatur haben wollte. Ich habe auch einige Argumentprüfungen hinzugefügt, um von einem frühen Ausfall mit vernünftigen Informationen bei unerwarteten Eingaben zu profitieren.
@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;
}
Sie können versuchen, es in eine Arraylist zu konvertieren, die addAll-Methode verwenden und dann wieder in ein Array konvertieren.
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
Hier eine mögliche Implementierung der von silvertab geschriebenen Pseudocode-Lösung in den Arbeitscode.
Danke 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;
}
}
Als nächstes folgt die Builder-Oberfläche.
Hinweis: Ein Builder ist erforderlich, da dies in Java nicht möglich ist
new T[size]
aufgrund der generischen Löschung:
public interface ArrayBuilderI<T> {
public T[] build(int size);
}
Hier ein konkreter Builder, der die Schnittstelle implementiert und ein Integer
Array erstellt:
public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {
@Override
public Integer[] build(int size) {
return new Integer[size];
}
}
Und zum Schluss die Anwendung / der 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]);
}
}
Beeindruckend! Viele komplexe Antworten hier, einschließlich einiger einfacher, die von externen Abhängigkeiten abhängen. wie wäre es so:
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]);
Dies funktioniert, aber Sie müssen Ihre eigene Fehlerprüfung einfügen.
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();
}
}
Es ist wahrscheinlich nicht das effizienteste, aber es basiert auf nichts anderem als Javas eigener API.
for
Schleife durch folgende zu ersetzen :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)
diese Option, um die erste for
Schleife zu überspringen . Spart Zeit proportional zur Größe von arr1
.
Dies ist eine konvertierte Funktion für ein String-Array:
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;
}
Wie wäre es einfach
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());
}
}
Und mach es einfach Array.concat(arr1, arr2)
. Solange arr1
und arr2
vom selben Typ sind, erhalten Sie ein weiteres Array desselben Typs, das beide Arrays enthält.
Eine generische statische Version, die die leistungsstarke System.arraycopy verwendet, ohne dass eine @ SuppressWarnings-Annotation erforderlich ist:
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;
}
Hier ist meine leicht verbesserte Version von Joachim Sauers concatAll. Es kann unter Java 5 oder 6 mit System.arraycopy von Java 6 verwendet werden, wenn es zur Laufzeit verfügbar ist. Diese Methode (IMHO) ist perfekt für Android, da sie unter Android <9 (ohne System.arraycopy) funktioniert, aber wenn möglich die schnellere Methode verwendet.
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;
}
Eine andere Art, über die Frage nachzudenken. Um zwei oder mehr Arrays zu verketten, müssen Sie alle Elemente jedes Arrays auflisten und dann ein neues Array erstellen. Das klingt so, als würde man ein erstellen List<T>
und es dann aufrufen toArray
. Einige andere Antworten verwenden ArrayList
, und das ist in Ordnung. Aber wie wäre es mit einer eigenen Implementierung? Es ist nicht schwer:
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);
}
Ich glaube, dass das oben Genannte den Lösungen entspricht, die verwendet werden System.arraycopy
. Ich denke jedoch, dass dieser seine eigene Schönheit hat.
Wie wäre es mit :
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()]);
}
Eine einfache Variante, die das Zusammenfügen von mehr als einem Array ermöglicht:
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()]);
}
Verwenden Sie nur die Javas-eigene API:
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]);
}
Dieser Code ist nicht der effizienteste, basiert jedoch nur auf Standard-Java-Klassen und ist leicht zu verstehen. Es funktioniert für eine beliebige Anzahl von String [] (sogar Null-Arrays).