Tuesday, May 29, 2012

How to concatenate two arrays in Java?


I need to concatenate two String arrays in Java.




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



What is the easiest way to do this?


Source: Tips4all

30 comments:

  1. I found a one-line solution from the good old Apache Commons Lang library. ArrayUtils.addAll(T[], T...). Code:

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

    ReplyDelete
  2. Here's a method that will concatenate 2 arrays of type T (replace the T in the code with your classname in question, this is just pseudocode not generics).

    T[] concat(T[] A, T[] B) {
    T[] C= new T[A.length+B.length];
    System.arraycopy(A, 0, C, 0, A.length);
    System.arraycopy(B, 0, C, A.length, B.length);

    return C;
    }


    (source: Sun Forum )

    ReplyDelete
  3. It's possible to write a fully generic version that can even be extended to concatenate any number of arrays. This versions require Java 6, as they use Arrays.copyOf()

    Both versions avoid creating any intermediary List objects and use System.arraycopy() to ensure that copying large arrays is as fast as possible.

    For two arrays it looks like this:

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


    And for a arbitrary number of arrays (>= 1) it looks like this:

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

    ReplyDelete
  4. I've recently fought problems with excessive memory rotation. If a and/or b are known to be commonly empty, here is another adaption of silvertab's code (generified too):

    private static <T> T[] concat(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;
    }


    (In either case, array re-usage behaviour shall be clearly JavaDoced!)

    ReplyDelete
  5. The Functional Java library has an array wrapper class that equips arrays with handy methods like concatenation.

    import static fj.data.Array.array;


    ...and then

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


    To get the unwrapped array back out, call

    String[] s = both.array();

    ReplyDelete
  6. Here's an adaptation of silvertab's solution, with generics retrofitted:

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


    NOTE: See Joachim's answer for a Java 6 solution. Not only does it eliminate the warning; it's also shorter, more efficient and easier to read!

    ReplyDelete
  7. Using the 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()]);
    }

    ReplyDelete
  8. Or with the loved Guava:

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

    ReplyDelete
  9. Using only Javas own 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]);
    }


    Now, this code ist not the most efficient, but it relies only on standard java classes and is easy to understand. It works for any number of String[] (even zero arrays).

    ReplyDelete
  10. Here a possible implementation in working code of the pseudo code solution written by silvertab.

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


    Following next is the builder interface.

    Note: A builder is necessary because in java it is not possible to do

    new T[size]

    due to generic type erasure:

    public interface ArrayBuilderI<T> {

    public T[] build(int size);
    }


    Here a concrete builder implementing the interface, building a Integer array:

    public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {

    @Override
    public Integer[] build(int size) {
    return new Integer[size];
    }
    }


    And finally the application / 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]);
    }
    }

    ReplyDelete
  11. This works, but you need to insert your own error checking.


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


    }

    It's probably not the most efficient, but it doesn't rely on anything other than Java's own API.

    ReplyDelete
  12. An easy, but inefficient, way to do this (generics not included):

    ArrayList baseArray = new ArrayList(Arrays.asList(array1));
    baseArray.addAll(Arrays.asList(array2));
    String concatenated[] = (String []) baseArray.toArray(new String[baseArray.size()]);

    ReplyDelete
  13. Object[] obj = {"hi","there"};
    Object[] obj2 ={"im","fine","what abt u"};
    Object[] obj3 = new Object[obj.length+obj2.length];

    for(int i =0;i<obj3.length;i++)
    obj3[i] = (i<obj.length)?obj[i]:obj2[i-obj.length];

    ReplyDelete
  14. Here's my slightly improved version of Joachim Sauer's concatAll. It can work on Java 5 or 6, using Java 6's System.arraycopy if it's available at runtime. This method (IMHO) is perfect for Android, as it work on Android <9 (which doesn't have System.arraycopy) but will use the faster method if possible.

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

    ReplyDelete
  15. If you'd like to work with ArrayLists in the solution, you can try this:

    public final String [] f(final String [] first, final String [] second) {
    // Assuming non-null for brevity.
    final ArrayList<String> resultList = new ArrayList<String>(Arrays.asList(first));
    resultList.addAll(new ArrayList<String>(Arrays.asList(second)));
    return resultList.toArray(new String [resultList.size()]);
    }

    ReplyDelete
  16. I tested below code and worked ok

    Also I'm using library: org.apache.commons.lang.ArrayUtils

    public void testConcatArrayString(){
    String[] a = null;
    String[] b = null;
    String[] c = null;
    a = new String[] {"1","2","3","4","5"};
    b = new String[] {"A","B","C","D","E"};

    c = (String[]) ArrayUtils.addAll(a, b);
    if(c!=null){
    for(int i=0; i<c.length; i++){
    System.out.println("c[" + (i+1) + "] = " + c[i]);
    }
    }
    }


    Regards

    ReplyDelete
  17. A simple variation allowing the joining of more than one 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()]);

    }

    ReplyDelete
  18. A type independent variation (UPDATED - thanks to Volley for instantiating T):

    @SuppressWarnings("unchecked")
    public static <T> T[] join(T[]...arrays) {

    final List<T> output = new ArrayList<T>();

    for(T[] array : arrays) {
    output.addAll(Arrays.asList(array));
    }

    return output.toArray((T[])Array.newInstance(arrays[0].getClass().getComponentType(), output.size()));

    }

    ReplyDelete
  19. /**
    * Concatenates two arrays.
    *
    * @param array1 - first array
    * @param array2 - second array
    * @param <T> - object class
    * @return array contatenation
    */
    public static <T> T[] concatenate(T[] array1, T... array2) {
    List<T> result = new ArrayList<T>();
    result.addAll(Arrays.asList(array1));
    result.addAll(Arrays.asList(array2));

    return result.toArray(array1);
    }

    ReplyDelete
  20. 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;
    }

    ReplyDelete
  21. Another one based on SilverTab's suggestion, but made to support x number of arguments and not require Java 6. It is also not generic, but I'm sure it could be made generic.


    private byte[] concat(byte[]... args) {
    int fulllength = 0;
    for (byte[] arrItem : args) {
    fulllength += arrItem.length;
    }

    byte[] retArray = new byte[fulllength];
    int start = 0;
    for (byte[] arrItem : args) {
    System.arraycopy(arrItem, 0, retArray, start, arrItem.length);
    start += arrItem.length;
    }
    return retArray;
    }

    ReplyDelete
  22. The easiest way i could find is as following :



    List allFiltersList = Arrays.asList(regularFilters);
    allFiltersList.addAll(Arrays.asList(preFiltersArray));
    Filter[] mergedFilterArray = (Filter[]) allFiltersList.toArray();

    ReplyDelete
  23. This is a converted function for a 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;
    }

    ReplyDelete
  24. Import java.util.*;

    String array1[] = {"bla","bla"};
    String array2[] = {"bla","bla"};

    ArrayList<String> tempArray = new ArrayList<String>(Arrays.asList(array1));
    tempArray.addAll(Arrays.asList(array2));
    String array3[] = films.toArray(new String[1]); (size will be overwritten if needed)

    You could replace String by a Type/Class of your liking

    Im sure this can be made shorter and better, but it works and im to lazy to sort it out further...

    ReplyDelete
  25. You can try this

    public static Object[] addTwoArray(Object[] objArr1, Object[] objArr2){
    int arr1Length = objArr1!=null && objArr1.length>0?objArr1.length:0;
    int arr2Length = objArr2!=null && objArr2.length>0?objArr2.length:0;
    Object[] resutlentArray = new Object[arr1Length+arr2Length];
    for(int i=0,j=0;i<resutlentArray.length;i++){
    if(i+1<=arr1Length){
    resutlentArray[i]=objArr1[i];
    }else{
    resutlentArray[i]=objArr2[j];
    j++;
    }
    }

    return resutlentArray;
    }


    U can type cast your array !!!!!!

    Hope it will help u

    Cheer :)

    ReplyDelete
  26. How about simply


    public static class Array {

    public static T[] concat(T[]... arrays) {
    ArrayList al = new ArrayList();
    for (T[] one : arrays)
    Collections.addAll(al, one);
    return (T[]) al.toArray(arrays[0].clone());
    }
    }


    And just do Array.concat(arr1, arr2). As long as arr1 and arr2 are of the same type, this will give you another array of the same type containing both arrays.

    ReplyDelete
  27. A solution 100% old java and without System.arraycopy (not available in GWT client for example):

    static String[] concat(String[]... arrays) {
    int lengh = 0;
    for (String[] array : arrays) {
    lengh += array.length;
    }
    String[] result = new String[lengh];
    int pos = 0;
    for (String[] array : arrays) {
    for (String element : array) {
    result[pos] = element;
    pos++;
    }
    }
    return result;
    }

    ReplyDelete
  28. In Haskell you can do something like that [a, b, c] ++ [d, e] to get [a, b, c, d, e]. These are Haskell lists concatenated but that'd very nice to see a similar operator in Java for arrays. Don't you think so ? That's elegant, simple, generic and it's not that difficult to implement.

    If you want to, I suggest you to have a look at Alexander Hristov's work in his Hacking the OpenJDK compiler. He explains how to modify javac source to create a new operator. His example consists in defining a '**' operator where i ** j = Math.pow(i, j). One could take that example to implement an operator that concatenates two arrays of same type.

    Once you do that, you are bound to your customized javac to compile your code but the generated bytecode will be understood by any JVM. Of course, you can implement your own array concatenatation method at your source level, there are many examples on how to do it in the other answers !

    There are so many useful operators that could be added, this one would be one of them.

    ReplyDelete
  29. Look at this elegant solution (if you need other type than char, change it):

    private static void concatArrays(char[] destination, char[]... sources) {
    int currPos = 0;
    for (char[] source : sources) {
    int length = source.length;
    System.arraycopy(source, 0, destination, currPos, length);
    currPos += length;
    }
    }


    You can concatenate a every count of arrays.

    ReplyDelete
  30. String[] both = Arrays.asList(first).addAll(Arrays.asList(second)).toArray();

    ReplyDelete