Как я могу объединить два массива в Java? - PullRequest
1243 голосов
/ 17 сентября 2008

Мне нужно объединить два String массива в Java.

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

Какой самый простой способ сделать это?

Ответы [ 58 ]

982 голосов
/ 17 сентября 2008

Я нашел однострочное решение из старой доброй библиотеки Apache Commons Lang.
ArrayUtils.addAll(T[], T...)

Код:

String[] both = ArrayUtils.addAll(first, second);
742 голосов
/ 17 сентября 2008

Вот простой метод, который объединит два массива и вернет результат:

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

Обратите внимание, что он не будет работать с примитивными типами данных, только с типами объектов.

Следующая немного более сложная версия работает как с объектными, так и с примитивными массивами. Это делается с помощью T вместо T[] в качестве типа аргумента.

Это также позволяет объединять массивы двух разных типов, выбирая наиболее общий тип в качестве типа компонента результата.

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

Вот пример:

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 }));
454 голосов
/ 24 апреля 2009

Можно написать полностью универсальную версию, которая может быть расширена для объединения любого числа массивов. Эти версии требуют Java 6, так как они используют Arrays.copyOf()

Обе версии избегают создания каких-либо промежуточных List объектов и используют System.arraycopy() для обеспечения максимально быстрого копирования больших массивов.

Для двух массивов это выглядит так:

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

А для произвольного числа массивов (> = 1) это выглядит так:

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;
}
392 голосов
/ 21 апреля 2014

Однострочник в Java 8:

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

Или:

String[] both = Stream.of(a, b).flatMap(Stream::of)
                      .toArray(String[]::new);
180 голосов
/ 09 марта 2011

Или с любимой Гуава :

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

Также есть версии для примитивных массивов:

  • 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)
57 голосов
/ 19 сентября 2008

Использование 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()]);
}
42 голосов
/ 11 апреля 2018

Вы можете добавить два массива в две строки кода.

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

Это быстрое и эффективное решение, которое будет работать для примитивных типов, так как оба метода перегружены.

Вам следует избегать решений, включающих ArrayLists, потоки и т. Д., Так как они должны будут выделять временную память без всякой полезной цели.

Вам следует избегать циклов for для больших массивов, так как они неэффективны. Встроенные методы используют чрезвычайно быстрые функции блочного копирования.

40 голосов
/ 11 октября 2011

Решение 100% старых java и без System.arraycopy (например, недоступно в GWT-клиенте):

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;
}
32 голосов
/ 17 сентября 2008

Я недавно боролся с проблемами с чрезмерным вращением памяти. Если известно, что a и / или b обычно пусты, вот еще одна адаптация кода silvertab (также обобщенного):

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

Edit: в предыдущей версии этого поста говорилось, что повторное использование массива должно быть четко задокументировано. Как указывает Мартен в комментариях, в целом было бы лучше просто удалить операторы if, что исключает необходимость иметь документацию. Но опять же, эти операторы if были главной целью этой конкретной оптимизации. Я оставлю этот ответ здесь, но будь осторожен!

27 голосов
/ 17 сентября 2008

Библиотека Functional Java имеет класс-обертку для массива, который оснащает массивы такими удобными методами, как конкатенация.

import static fj.data.Array.array;

... а затем

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

Чтобы вернуть развернутый массив, вызовите

String[] s = both.array();
...