Wie kann ich zwei Arrays in Java verketten?

1366

Ich muss zwei StringArrays in Java verketten .

void f(String[] first, String[] second) {
    String[] both = ???
}

Was ist der einfachste Weg, dies zu tun?

Antti Kissaniemi
quelle
3
Bytes.concat von Guava
Ben Seite
1
Ich sehe hier viele Antworten, aber die Frage ist so formuliert ("einfachster Weg"?), Dass es nicht möglich ist, die beste Antwort anzugeben ...
Artur Opalinski
2
Dutzende von Antworten hier kopieren die Daten in ein neues Array, weil dies verlangt wurde - aber das Kopieren von Daten, wenn dies nicht unbedingt erforderlich ist, ist eine schlechte Sache, insbesondere in Java. Behalten Sie stattdessen die Indizes im Auge und verwenden Sie die beiden Arrays so, als wären sie verbunden. Ich habe eine Lösung hinzugefügt, die die Technik veranschaulicht.
Douglas Held
12
Die Tatsache, dass eine Frage wie diese derzeit 50 verschiedene Antworten hat, lässt mich fragen, warum Java nie eine einfache array1 + array2Verkettung erhalten hat.
JollyJoker
2
Sie können es in zwei Zeilen Standard-Java perfekt und sehr effizient ausführen (siehe meine Antwort), sodass mit einer einzigen Methode nicht viel erreicht werden kann. All diese seltsamen und wunderbaren Lösungen sind Zeitverschwendung.
rghome

Antworten:

1093

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);
Antti Kissaniemi
quelle
175
Wie ist es "Betrug", wenn es die Frage beantwortet? Sicher, eine zusätzliche Abhängigkeit ist für diese spezielle Situation wahrscheinlich übertrieben, aber es schadet nicht, darauf hinzuweisen, dass sie existiert, zumal es in Apache Commons so viele hervorragende Funktionen gibt.
Rob
33
Ich stimme zu, dies beantwortet die Frage nicht wirklich. Hochrangige Bibliotheken können großartig sein, aber wenn Sie eine effiziente Methode erlernen möchten, sollten Sie sich den Code ansehen, den die Bibliotheksmethode verwendet. In vielen Situationen können Sie auch nicht einfach eine andere Bibliothek im Produkt im laufenden Betrieb durchsuchen.
AdamC
76
Ich denke, das ist eine gute Antwort. POJO-Lösungen wurden ebenfalls bereitgestellt, aber wenn das OP Apache Commons bereits in seinem Programm verwendet (angesichts seiner Popularität insgesamt möglich), kennt er diese Lösung möglicherweise immer noch nicht. Dann würde er nicht "eine Abhängigkeit für diese eine Methode hinzufügen", sondern eine vorhandene Bibliothek besser nutzen.
Adam
14
Wenn Sie immer befürchten, keine Bibliothek für eine einzelne Methode hinzuzufügen, werden niemals neue Bibliotheken hinzugefügt. Angesichts der hervorragenden Dienstprogramme in Apache Commons empfehle ich dringend, sie hinzuzufügen, wenn der erste Anwendungsfall auftritt.
Hindol
6
Die Verwendung von Apache Commons sollte niemals als "Betrug" bezeichnet werden. Ich bezweifle die Vernunft von Entwicklern, die davon ausgehen, dass es sich um eine unnötige Abhängigkeit handelt.
Jeryl Cook
768

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 Tanstelle 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 }));
Lii
quelle
1
Ich mag diesen Vorschlag, da er weniger von den neuesten Java-Versionen abhängig ist. In meinen Projekten stecke ich häufig in älteren Versionen von Java- oder CLDC-Profilen fest, in denen einige der von Antti genannten Funktionen nicht verfügbar sind.
Kvn
4
Die folgende Zeile wird den generischen Teil
unterbrechen
Es wäre schön, wenn Sie die Annotation @SuppressWarnings nicht verwenden müssten - ich werde unten eine Lösung dafür veröffentlichen.
Beaudet
+1 für 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.
Blake
1
ha, nenn mich einen Puristen, aber ich bevorzuge sauberen Code, der keine Unterdrückung von Warnungen erfordert, um Warnungen zu entfernen
beaudet
475

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 Listund 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;
}
Joachim Sauer
quelle
10
@djBO: Für primitiv typisierte Arrays müssten Sie für jeden Typ eine Überladung vornehmen: Kopieren Sie einfach den Code und ersetzen Sie jeden Tdurch byte(und verlieren Sie den <T>).
Joachim Sauer
Können Sie mir bitte sagen, wie ich den Operatortyp <T> in meiner Klasse verwenden soll?
Johnydep
6
Ich würde dies am Anfang hinzufügen, nur um defensiv zu sein. if (first == null) {if (second == null) {return null; } return second; } if (second == null) {return first; }
Marathon
4
@djBo: was ist mit:ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
Sam Goldberg
18
Es gibt einen Fehler in diesem Ansatz, der offensichtlich wird, wenn Sie diese Funktionen mit Arrays verschiedener Komponententypen aufrufen, z. B. concat(ai, ad)wo aiist Integer[]und adist Double[]. (In diesem Fall wird die Typ - Parameter <T>werden gelöst <? extends Number>durch den Compiler.) Das Array erstellt von Arrays.copyOfdem Komponententyp des ersten Arrays, dh Integerin diesem Beispiel. Wenn die Funktion das zweite Array kopieren ArrayStoreExceptionwill , wird ein ausgelöst. Die Lösung besteht darin, einen zusätzlichen Class<T> typeParameter zu haben .
T-Bull
457

Verwenden Streamin 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));
Lii
quelle
28
Wie effizient ist das?
Supuhstar
8
Eine Lektüre wert: jaxenter.com/… tl; dr - Streams können performant sein oder nicht, es hängt davon ab, was Sie mit ihnen machen und welche Einschränkungen das Problem hat (ist das nicht immer die Antwort? Lol)
Trevor Brown
6
Wenn a oder b Arrays primitiver Typen sind, müssen ihre Streams außerdem so sein, .boxed()dass sie vom Typ sind Streamund nicht z. B., IntStreamdie nicht als Parameter an übergeben werden können Stream.concat.
Will Hardwick-Smith
17
@ Will Hardwick-Smith: Nein, Sie müssen nur die richtige Stream-Klasse auswählen, zB wenn aund bsind int[], verwenden Sieint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
Holger
3
@Supuhstar: Es ist wahrscheinlich nicht so schnell wie 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.
Lii
191

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)
KARASZI István
quelle
So sehr ich Guava liebe, die Methode von Apache Commons geht besser mit Nullables um.
Ravi Wallau
7
Es ist zwar gut, Bibliotheken zu verwenden, aber es ist bedauerlich, dass das Problem weg abstrahiert wurde. Daher bleibt die zugrunde liegende Lösung schwer fassbar.
user924272
51
Was ist das Problem mit der Abstraktion? Keine Ahnung, was es mit der Neuerfindung des Rades auf sich hat. Wenn Sie das Problem kennenlernen möchten, überprüfen Sie die Quelle oder lesen Sie weiter. Professioneller Code sollte Bibliotheken auf hoher Ebene verwenden, viel besser, wenn er in Google entwickelt wurde!
Breno Salgado
@ RaviWallau Könnten Sie einen Link zu der Klasse erstellen, die dies tut?
Sébastien Tromp
1
@ SébastienTromp Es ist die Top-Lösung für diese Frage - ArrayUtils.
Ravi Wallau
70

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 forSchleifen für große Arrays vermeiden, da diese nicht effizient sind. Die integrierten Methoden verwenden Blockkopierfunktionen, die extrem schnell sind.

rghome
quelle
1
Dies ist eine der besten Lösungen. 100% Standard Java. Schnell / effizient. Sollte mehr Upvotes bekommen!
Shebla Tsama
58

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()]);
}
Fabian Steeg
quelle
13
Einfach, aber ineffizient, da ein Array für ArrayList erstellt und dann ein anderes für die toArray-Methode generiert wird. Aber immer noch gültig, da es einfach zu lesen ist.
PhoneixS
1
Gilt für Strings und Objekte (wie von der Frage gewünscht), aber es gibt keine addAll-Methode für Primärtypen (als Ints)
joro
Wie in diesem Artikel ausgeführt , ist die Verwendung 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.
Holger
42

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;
}
Francois
quelle
meins für File [] überarbeitet, aber es ist das gleiche. Vielen Dank für Ihre Lösung
ShadowFlame
5
Wahrscheinlich aber ziemlich ineffizient.
JonasCz
Möglicherweise möchten Sie nullSchecks hinzufügen . Und vielleicht setzen Sie einige Ihrer Variablen auf final.
Tripp Kinetics
@ TrippKinetics- nullÜberprüfungen würden NPEs verbergen, anstatt sie anzuzeigen , und die Verwendung von final für lokale Variablen hat (noch) keinen Vorteil.
Maarten Bodewes
1
@ Maarten Bodewes Ich denke, Sie werden feststellen (wenn Sie es vergleichen, was ich habe), dass das for-each in späten Versionen von Java zur gleichen Zeit wie die indizierte Schleife ausgeführt wird. Der Optimierer kümmert sich darum.
rghome
33

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!

Volleyball
quelle
5
Dies bedeutet jedoch, dass Sie dasselbe Array zurückgeben und durch Ändern eines Werts für das zurückgegebene Array den Wert an derselben Position des zurückgegebenen Eingabearrays ändern.
Lorenzo Boccaccia
Ja - siehe Kommentar am Ende meines Beitrags zur Wiederverwendung von Arrays. Der durch diese Lösung verursachte Wartungsaufwand hat sich in unserem speziellen Fall gelohnt, aber in den meisten Fällen sollte wahrscheinlich defensives Kopieren verwendet werden.
Volley
Lorenzo / volley, können Sie erklären, welcher Teil des Codes die Wiederverwendung des Arrays verursacht? Ich dachte, System.arraycopykopiert den Inhalt des Arrays?
Rosdi Kasim
4
Ein Aufrufer würde normalerweise erwarten, dass ein Aufruf von concat () ein neu zugewiesenes Array zurückgibt. Wenn entweder a oder b null ist, gibt concat () jedoch eines der übergebenen Arrays zurück. Diese Wiederverwendung kann unerwartet sein. (Ja, Arraycopy kopiert nur. Die Wiederverwendung erfolgt durch direkte Rückgabe von a oder b.)
Volley
Der Code sollte so selbsterklärend wie möglich sein. Personen, die den Code lesen, sollten nicht das JavaDoc einer aufgerufenen Funktion nachschlagen müssen, um herauszufinden, dass es eine Sache für eine bestimmte Bedingung und etwas anderes für eine andere tut. Kurz gesagt: Sie können solche Designprobleme im Allgemeinen nicht mit einem Kommentar beheben. Nur die beiden ifAussagen wegzulassen, wäre die einfachste Lösung.
Maarten Bodewes
27

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();
Apocalisp
quelle
27
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));

both.toArray(new String[0]);
Nick-s
quelle
3
Die Antwort ist großartig, aber ein bisschen kaputt. Um es perfekt zu machen, sollten Sie ein Array des Typs, den Sie benötigen, an Array () übergeben. Im obigen Beispiel sollte der Code lauten: both.toArray (neuer String [0]) Siehe: stackoverflow.com/questions/4042434/…
Ronen Rabinovici
Ich weiß nicht, warum diese Antwort nicht höher bewertet wird ... obwohl sie die von @RonenRabinovici
drmrbrewer
4
Oder besser, ohne unnötige Zuweisung eines Arrays mit der Länge Null : both.toArray(new String[both.size()]);)
Honza
1
@ Honza empfohlen zu lesen
Holger
Hallo @Honza, ist es möglich, dasselbe zu tun, um ein primitives Integer-Array in 3 Zeilen zurückzugeben?
jump_monkey
18

Ein anderer Weg mit Java8 unter Verwendung von Stream

  public String[] concatString(String[] a, String[] b){ 
    Stream<String> streamA = Arrays.stream(a);
    Stream<String> streamB = Arrays.stream(b);
    return Stream.concat(streamA, streamB).toArray(String[]::new); 
  }
Vaseph
quelle
17

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!

Volleyball
quelle
Sie können die Warnung für diese Methode unterdrücken, aber ansonsten können Sie nicht viel tun. Arrays und Generika mischen sich nicht wirklich.
Dan Dyer
3
Die deaktivierte Warnung kann entfernt werden, wenn Sie Arrays.copyOf () verwenden. Siehe meine Antwort für eine Implementierung.
Joachim Sauer
@ SuppressWarnings ("nicht markiert")
Mark Renouf
13

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.

Raj S. Rusia
quelle
11

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;
}
Zalumon
quelle
Ich würde die Länge in derselben Schleife zusammenfassen, in der Sie Ihre Nullprüfung durchführen - aber dies ist eine wirklich gute Zusammenfassung der anderen Antworten hier. Ich glaube, es behandelt sogar intrinsische Typen wie "int", ohne sie in Integer-Objekte zu ändern, was wirklich der EINZIGE Grund ist, sie als Arrays zu behandeln, anstatt nur alles in ArrayLists zu ändern. Ihre Methode könnte auch 2 Arrays und einen (...) Parameter verwenden, sodass der Aufrufer weiß, dass er mindestens zwei Arrays übergeben muss, bevor er sie ausführt, und den Fehler sieht, aber dies erschwert den Schleifencode ....
Bill K.
11

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();
Paul
quelle
Gute Lösung - wäre besser, wenn der Code überarbeitet würde, um Arrays insgesamt zugunsten von ArrayLists zu vermeiden, aber das liegt außerhalb der Kontrolle der "Antwort" und bis zum Fragesteller.
Bill K
Ich zähle, dass es 4 zusätzliche temporäre Objekte benötigt, um zu arbeiten.
rghome
@rghome, zumindest ist keine zusätzliche Bibliothek erforderlich, um eine so einfache Aufgabe zu implementieren
Farid
9

Mit Java 8+ Streams können Sie die folgende Funktion schreiben:

private static String[] concatArrays(final String[]... arrays) {
    return Arrays.stream(arrays)
         .flatMap(Arrays::stream)
         .toArray(String[]::new);
}
Keisar
quelle
7

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 IntegerArray 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]);
   }
}
hpgisler
quelle
7

Dies sollte einzeilig sein.

public String [] concatenate (final String array1[], final String array2[])
{
    return Stream.concat(Stream.of(array1), Stream.of(array2)).toArray(String[]::new);
}
avigaild
quelle
6

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]);
Doles
quelle
1
..Aber ineffizient und langsam.
JonasCz - Wiedereinsetzung Monica
6

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.

Kleber
quelle
2
+1. Es wäre besser, die zweite forSchleife durch folgende zu ersetzen :for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
Bancer
Verwenden Sie String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)diese Option, um die erste forSchleife zu überspringen . Spart Zeit proportional zur Größe von arr1.
John Meyer
5

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;
}
Oritm
quelle
5

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 arr1und arr2vom selben Typ sind, erhalten Sie ein weiteres Array desselben Typs, das beide Arrays enthält.

Ephraim
quelle
Aus Leistungsgründen würde ich die endgültige Größe der ArrayList vorberechnen, da ArrayList per Definition ein neues Array zuweist und seine Elemente jedes Mal kopiert, wenn das aktuelle Array voll ist. Andernfalls würde ich direkt zu LinkedList gehen, die kein solches Problem hat
usr-local-ΕΨΗΕΛΩΝ
5

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;
}
Beaudet
quelle
4
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;
}
Sujay
quelle
4

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;
  }
Candrews
quelle
1
Gute allgemeine Idee, aber für jeden, der sie implementiert: Ich würde eine copyOf- und eine non-copyOf-Version einer Version vorziehen, die beides durch Reflexion tut.
rektide
4

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.

Erdmotor
quelle
4

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()]);
}
clément francomme
quelle
4

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()]);
}
Damo
quelle
3

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).

Kiwi
quelle
15
Musste dieses für all die unnötige Listenobjekterstellung herabstimmen.
Outlaw Programmer