Hoe kan ik twee arrays in Java samenvoegen?

Ik moet twee String-arrays samenvoegen in Java.

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

Wat is de gemakkelijkste manier om dit te doen?


Antwoord 1, autoriteit 100%

Ik heb een éénregelige oplossing gevonden uit de goede oude Apache Commons Lang-bibliotheek.
ArrayUtils.addAll(T[], T...)

Code:

String[] both = ArrayUtils.addAll(first, second);

Antwoord 2, autoriteit 66%

Hier is een eenvoudige methode die twee arrays samenvoegt en het resultaat retourneert:

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;
}

Houd er rekening mee dat het niet werkt met primitieve gegevenstypen, alleen met objecttypen.

De volgende iets gecompliceerdere versie werkt met zowel object- als primitieve arrays. Het doet dit door Tte gebruiken in plaats van T[]als argumenttype.

Het maakt het ook mogelijk om arrays van twee verschillende typen samen te voegen door het meest algemene type te kiezen als het componenttype van het resultaat.

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 is een voorbeeld:

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 }));

Antwoord 3, autoriteit 44%

Streamin Java 8:

String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
                      .toArray(String[]::new);

Of zo, met flatMap:

String[] both = Stream.of(a, b).flatMap(Stream::of)
                      .toArray(String[]::new);

Om dit voor een generiek type te doen, moet je reflectie gebruiken:

@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
    size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));

Antwoord 4, autoriteit 41%

Het is mogelijk om een volledig generieke versie te schrijven die zelfs kan worden uitgebreid om een willekeurig aantal arrays samen te voegen. Deze versies vereisen Java 6, omdat ze Arrays.copyOf()

Beide versies vermijden het maken van tussenliggende List-objecten en gebruiken System.arraycopy()om ervoor te zorgen dat het kopiëren van grote arrays zo snel mogelijk gaat.

Voor twee arrays ziet het er als volgt uit:

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;
}

En voor een willekeurig aantal arrays (>=1) ziet het er als volgt uit:

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;
}

Antwoord 5, autoriteit 17%

of met de geliefde Guava :

String[] both = ObjectArrays.concat(first, second, String.class);

Er zijn ook versies voor primitieve 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)

Antwoord 6, Autoriteit 10%

U kunt de twee arrays in twee regels code toevoegen.

String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);

Dit is een snelle en efficiënte oplossing en zal werken voor primitieve typen, evenals de betrokken methoden zijn overbelast.

U moet oplossingen vermijden met arraylisten, streams, enz. Omdat deze tijdelijk geheugen nodig hebben voor geen nuttig doel.

U moet vermijden forloops voor grote arrays, omdat deze niet efficiënt zijn. De ingebouwde methoden gebruiken blokkopiefuncties die extreem snel zijn.


Antwoord 7, Autoriteit 5%

Gebruik van de 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()]);
}

Antwoord 8, autoriteit 4%

Een oplossing 100% oude javaen zonderSystem.arraycopy(bijvoorbeeld niet beschikbaar in de GWT-client):

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;
}

Antwoord 9, autoriteit 3%

Ik heb onlangs problemen gehad met overmatige geheugenrotatie. Als bekend is dat a en/of b vaak leeg zijn, is hier nog een aanpassing van de code van silvertab (ook gegenereerd):

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;
}

Bewerken: in een eerdere versie van dit bericht stond dat hergebruik van arrays zoals dit duidelijk moet worden gedocumenteerd. Zoals Maarten in de opmerkingen aangeeft, zou het over het algemeen beter zijn om de if-statements gewoon te verwijderen, waardoor de noodzaak voor documentatie vervalt. Maar nogmaals, die if-statements waren in de eerste plaats het hele punt van deze specifieke optimalisatie. Ik laat dit antwoord hier achter, maar wees voorzichtig!


Antwoord 10, autoriteit 2%

De Functionele Java-bibliotheek heeft een array-wrapperklasse die arrays uitrust met handige methoden zoals concatenatie.

import static fj.data.Array.array;

…en dan

Array<String> both = array(first).append(array(second));

Om de uitgepakte array weer tevoorschijn te halen, bel

String[] s = both.array();

Antwoord 11, autoriteit 2%

ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));
both.toArray(new String[0]);

Antwoord 12, autoriteit 2%

Een andere manier met Java8 met 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); 
  }

Antwoord 13

Hier is een aanpassing van de oplossing van silvertab, met achteraf aangebrachte generieke geneesmiddelen:

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;
}

OPMERKING: zie Joachims antwoordvoor een Java 6-oplossing. Het elimineert niet alleen de waarschuwing; het is ook korter, efficiënter en gemakkelijker te lezen!


Antwoord 14

Je zou kunnen proberen het te converteren naar een Arraylist en de addAll-methode te gebruiken en vervolgens terug te converteren naar een array.

List list = new ArrayList(Arrays.asList(first));
  list.addAll(Arrays.asList(second));
  String[] both = list.toArray();

Antwoord 15

Als je deze manier gebruikt, hoef je geen klasse van derden te importeren.

Als u String

wilt samenvoegen

Voorbeeldcode voor het samenvoegen van twee 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;
    }

Als u Int

wilt samenvoegen

Voorbeeldcode voor het samenvoegen van twee Integer-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 is de hoofdmethode

   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));
        }
    }  

We kunnen op deze manier ook gebruiken.


Antwoord 16

Vergeef me alsjeblieft voor het toevoegen van nog een andere versie aan deze al lange lijst. Ik keek naar elk antwoord en besloot dat ik echt een versie wilde met slechts één parameter in de handtekening. Ik heb ook een aantal argumentencontrole toegevoegd om te profiteren van vroege mislukking met verstandige informatie in geval van onverwachte invoer.

@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;
}

Antwoord 17

Met Java 8+ streams kun je de volgende functie schrijven:

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

Antwoord 18

Hier een mogelijke implementatie in werkende code van de pseudo-code-oplossing geschreven door silvertab.

Bedankt 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;
   }
}

Hierna volgt de bouwer-interface.

Opmerking: een builder is nodig omdat het in Java niet mogelijk is om

new T[size]

vanwege het wissen van het algemene type:

public interface ArrayBuilderI<T> {
   public T[] build(int size);
}

Hier een concrete bouwer die de interface implementeert en een Integerarray bouwt:

public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {
   @Override
   public Integer[] build(int size) {
      return new Integer[size];
   }
}

en ten slotte de toepassing / 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]);
   }
}

Antwoord 19

Dit zou een voering moeten zijn.

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

Antwoord 20

WOW! Veel complexe antwoorden hier inclusief enkele eenvoudige die afhankelijk zijn van externe afhankelijkheden. Hoe zit het met het doen als dit:

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]);

Antwoord 21

Dit werkt, maar u moet uw eigen foutcontrole invoegen.

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();
    }
}

Het is waarschijnlijk niet de meest efficiënte, maar het is niet afhankelijk van iets anders dan Java’s eigen API.


Antwoord 22

Dit is een geconverteerde functie voor een 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;
}

Antwoord 23

Wat dacht je van gewoon

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());
    }
}

En doe gewoon Array.concat(arr1, arr2). Zolang arr1en arr2van hetzelfde type zijn, krijg je een andere array van hetzelfde type die beide arrays bevat.


Antwoord 24

Een eenvoudige variatie die het samenvoegen van meer dan één array mogelijk maakt:

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

Antwoord 25

Een generieke statische versie die gebruikmaakt van de goed presterende System.arraycopy zonder een @SuppressWarnings-annotatie:

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;
}

Antwoord 26

Alleen Java’s eigen API gebruiken:


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

Deze code is niet de meest efficiënte, maar hij vertrouwt alleen op standaard Java-klassen en is gemakkelijk te begrijpen. Het werkt voor elk aantal String[] (zelfs nul arrays).


Antwoord 27

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;
}

Antwoord 28

Hier is mijn enigszins verbeterde versie van Joachim Sauer’s Concatall. Het kan werken op Java 5 of 6, met behulp van Java 6’s System.arraycopy als het op runtime beschikbaar is. Deze methode (IMHO) is perfect voor Android, omdat het op Android & LT; 9 werkt (wat geen System.arraycopy) heeft, maar de snellere methode gebruikt indien mogelijk.

 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;
  }

Antwoord 29

Een andere manier om over de vraag na te denken. Om twee of meer arrays samen te voegen, hoef je alleen maar alle elementen van elke array op te sommen en vervolgens een nieuwe array te bouwen. Dit klinkt als een List<T>maken en er vervolgens toArrayop aanroepen. Sommige andere antwoorden gebruiken ArrayList, en dat is prima. Maar hoe zit het met het implementeren van onze eigen? Het is niet moeilijk:

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);
}

Ik geloof dat het bovenstaande equivalent is aan oplossingen die System.arraycopygebruiken. Maar ik denk dat deze zijn eigen schoonheid heeft.


Antwoord 30

Wat dacht je van:

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

Other episodes