views:

49286

answers:

18

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?

+69  A: 

Here's a method that will concatenate 2 arrays of type T

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 )

silvertab
You should probably add a remark, that one has to replace the T with the correct type.
jrudolph
no, he should start code with something like public static <T> T[]...
Slartibartfast
How the heck did this get upvoted? It doesn't even compile! You can instantiate an array of type 'T' because of erasure.
Outlaw Programmer
It got up-voted because it's the right idea. It may not be syntactically correct, but it illustrates which direction to go.
Daniel Spiewak
it should compile, because "T" isn't a generic type in his example.
cd1
-1 T is a generic type, and this code is not working.. please, test before upvote.
Tom Brito
+68  A: 

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

String[] both = ArrayUtils.addAll(first, second);
Antti Sykäri
i (heart) apache commons
Stu Thompson
I dunno, this is kind of cheating. I think most people probably won't want the extra dependency for this one method.
Outlaw Programmer
How is it "cheating" if it answers the question? Sure, having an extra dependency is probably overkill for this specific situation, but no harm is done in calling out that it exists, especially since there's so many excellent bits of functionality in Apache Commons.
Rob
I agree, this isn't really answering the question. High level libraries can be great, but if you want to learn an efficient way to do it, you want to look at the code the library method is using. Also, in many situations, you can't just through another library in the product on the fly.
AdamC
I think this is a good answer. POJO solutions have also been provided, but if the OP is using Apache Commons in their program already (altogether possible considering its popularity) he may still not know this solution. Then he wouldn't be "adding a dependency for this one method," but would be making better use of an existing library.
Adam
+4  A: 

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();
Apocalisp
+5  A: 

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

Had to downvote this one for all the unnecessary List object creation.
Outlaw Programmer
+7  A: 

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!

volley
You can suppress the warning for this method, but other than that there isn't much you can do. Arrays and generics don't really mix.
Dan Dyer
The unchecked warning can be eliminated if you use Arrays.copyOf(). See my answer for an implementation.
Joachim Sauer
Nice, updating to reflect this. Thanks!
volley
@SuppressWarnings("unchecked")
Mark Renouf
+17  A: 

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

volley
this however means that you are returning the same array and changing a value on the returned array changes the value in the same position of the input array returned.
Lorenzo Boccaccia
Yes - see comment at the end of my post regarding array re-usage. The maintenance overhead imposed by this solution was worth it in our particular case, but defensive copying should probably be used in most cases.
volley
Lorenzo / volley, can you explain which part in the code that cause array re-usage? I thought `System.arraycopy` copies the content of the array?
Rosdi
A caller would normally expect a call to concat() to return a newly allocated array. If either a or b is null, concat() will however return one of the arrays passed into it. This re-usage is what may be unexpected. (Yep, arraycopy only does copying. The re-usage comes from returning either a or b directly.)
volley
A: 

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

Richard
This suggestion is wrong for at least two reasons:List.addAll() returns a boolean, so you can't chain the calls as you have shown.Arrays.asList() returns an array-backed List that is not resizeable, so its addAll() method throws an UnsupportedOperationException.
mhagger
+5  A: 

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[] {});
}
Fabian Steeg
While this is correct, it takes up a lot of space. At least the ArrayList should be set to the correct (known) size on construction.
Daniel Schneller
Thanks, I've updated the answer.
Fabian Steeg
A: 

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()]);
}
Bob Cross
A: 

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

+1  A: 
glue
+1. It would be better to replace the second `for` loop with that: `for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}`
bancer
+21  A: 

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;
}
Joachim Sauer
+1 You probably can't get better than that.
Helper Method
+2  A: 

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()]);
MetroidFan2002
A: 

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

}
Damo
A: 

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

}
Damo
T[] return type?
dotjoe
I still like Joachim Sauer's solution better.
Michael Myers
I'm still on Java 5 so can't use Arrays.copyOf() as Joachim is doing.
Damo
A: 

Some of the solutions above dont work for primitive types specifically byte. Can you tell me an implementation which works for the byte[]

byte[] concat(byte[] a, byte[] b_) {byte[] result = new byte[a.length + b.length]; System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result;}
Carl Manaster
Thanks for the solution. I did get this one but I was looking for one generic solution both for the Object as well as the primitive types.Is it possible to have one
+1  A: 

I don't know why the top-rated answer is rated so high (and why can't I comment on it).

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

doesn't even compile as there is no overloaded addAll which returns a String array.

Kutzi
+1  A: 
/**
 * 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);
}
Bina