Как я могу объединить два массива в Java?


1366

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

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

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


3
Bytes.concat из Гуавы
Бен Пейдж

1
Я вижу много ответов здесь, но вопрос настолько сформулирован («самый простой способ»?), Что он не позволяет указать лучший ответ ...
Артур Опалински

2
Десятки ответов здесь - это копирование данных в новый массив, потому что это то, что было запрошено, но копирование данных, когда в этом нет особой необходимости, плохо, особенно в Java. Вместо этого следите за индексами и используйте два массива, как если бы они были объединены. Я добавил решение, иллюстрирующее технику.
Дуглас провел

12
Тот факт, что на такой вопрос в настоящее время есть 50 разных ответов, заставляет задуматься, почему в Java никогда не было простой array1 + array2конкатенации.
JollyJoker

2
Вы можете сделать это очень хорошо и очень эффективно в двух строчках стандартной Java (см. Мой ответ), так что при наличии одного метода сделать это не так уж и много. Все эти странные и чудесные решения - пустая трата времени.
августа

Ответы:


1093

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

Код:

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

175
Как это «обманывать», если он отвечает на вопрос? Несомненно, наличие дополнительной зависимости, вероятно, является избыточным для этой конкретной ситуации, но не будет никакого вреда, если вы объявите, что она существует, тем более что в Apache Commons так много отличных функциональных возможностей.
Роб

33
Я согласен, это не совсем ответ на вопрос. Библиотеки высокого уровня могут быть хорошими, но если вы хотите изучить эффективный способ сделать это, вы хотите посмотреть на код, который использует метод библиотеки. Кроме того, во многих ситуациях вы не можете просто просмотреть другую библиотеку в продукте на лету.
AdamC

76
Я думаю, что это хороший ответ. Также были предоставлены решения POJO, но если ОП уже использует Apache Commons в своей программе (что вполне возможно, учитывая его популярность), он все еще может не знать об этом решении. Тогда он не будет «добавлять зависимость для этого одного метода», но будет лучше использовать существующую библиотеку.
Адам

14
Если вы всегда беспокоитесь о том, чтобы не добавлять библиотеку для одного метода, новые библиотеки никогда не будут добавлены. Учитывая отличные утилиты, представленные в Apache Commons, я настоятельно рекомендую добавлять его при появлении самого первого варианта использования.
Хиндол

6
использование Apache Commons никогда не должно называться «обманом», я подвергаю сомнению здравомыслие разработчиков, которые считают его ненужной зависимостью.
Джерил Кук

768

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

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

1
Мне нравится это предложение, поскольку оно меньше зависит от последних версий Java. В моих проектах я часто зацикливаюсь на использовании старых версий профилей Java или CLDC, где некоторые из перечисленных Antti средств недоступны.
квн

4
Следующая строка будет разбивать общую часть: concatenate (new String [] {"1"}, new Object [] {new Object ()})
dragon66

было бы неплохо не использовать аннотацию @SuppressWarnings - решение для этого я опубликую ниже.
Бодет

+1 за Array.newInstance(a.getClass().getComponentType(), aLen + bLen);. Я удивительно никогда не видел этого раньше. @beaudet Я думаю, что аннотация здесь хорошо, учитывая, почему она подавляется.
Блейк

1
ха, называй меня пуристом, но я предпочитаю чистый код, который не требует подавления предупреждений для удаления предупреждений
beaudet

475

Можно написать полностью универсальную версию, которая может быть расширена для объединения любого числа массивов. Эти версии требуют 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;
}

10
@djBO: для массивов с примитивными типами вам нужно было бы сделать перегрузку для каждого типа: просто скопируйте код и замените каждый Tна byte(и потеряйте <T>).
Иоахим Зауэр

Можете ли вы сказать мне, как использовать тип оператора <T> в моем классе?
Johnydep

6
Я бы добавил это в начало, просто для защиты. if (first == null) {if (second == null) {return null; } верните секунду; } if (second == null) {return first; }
марафон

4
@djBo: как насчет:ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
Сэм Голдберг

18
В этом подходе есть ошибка, которая становится очевидной, если вы вызываете эти функции с массивами разных типов компонентов, например concat(ai, ad), где aiесть Integer[]и adесть Double[]. (В этом случае параметр типа <T>разрешается <? extends Number>компилятором.) Созданный массив Arrays.copyOfбудет иметь тип компонента первого массива, т.е. Integerв этом примере. Когда функция собирается скопировать второй массив, ArrayStoreExceptionбудет сгенерировано. Решение состоит в том, чтобы иметь дополнительный Class<T> typeпараметр.
T-Bull

457

Использование Streamв Java 8:

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

Или вот так, используя flatMap:

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

Чтобы сделать это для универсального типа, вы должны использовать отражение:

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

28
Насколько это эффективно?
Supuhstar

8
Стоит прочитать: jaxenter.com/… tl; dr - потоки могут быть эффективными или нет, это зависит от того, что вы делаете с ними, и ограничений проблемы (разве это не всегда ответ? Lol)
Тревор Браун

6
Кроме того, если a или b являются массивами примитивных типов, их потоки должны быть .boxed()такими, чтобы они имели тип, Streamа не, например, IntStreamкоторые нельзя было бы передать в качестве параметра Stream.concat.
Уилл Хардвик-Смит

17
@Will Hardwick-Smith: нет, вам нужно только выбрать правильный класс потока, например, если aи bесть int[], используйтеint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
Хольгер

3
@Supuhstar: Это, вероятно, не так быстро, как System.arrayCopy. Но не особенно медленно. Возможно, вам придется делать это очень много раз с огромными массивами в действительно чувствительных к производительности контекстах, чтобы разница во времени выполнения имела значение.
Лии

192

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

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)

Как бы я ни любил Guava, метод Apache Commons лучше справляется с обнуляемыми значениями.
Рави Валлау

7
Хотя использовать библиотеки полезно, к сожалению, проблема была устранена. Поэтому основное решение остается неуловимым.
user924272

51
В чем проблема с абстракцией? Не знаю, в чем дело с изобретением колеса здесь, если вы хотите узнать проблему, проверьте источник или прочитайте его. Профессиональный код должен использовать библиотеки высокого уровня, гораздо лучше, если он разработан внутри Google!
Брено Сальгадо

@RaviWallau Не могли бы вы дать ссылку на класс, который делает это?
Себастьян Тромп

1
@ SébastienTromp Это лучшее решение для этого вопроса - ArrayUtils.
Рави Валлау

70

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

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

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

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

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


1
Это одно из лучших решений. 100% стандартная Java. Fast / эффективный. Должен получить больше голосов!
Шебла Цама

58

Использование 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()]);
}

13
Просто, но неэффективно, поскольку он создает массив для ArrayList, а затем генерирует другой для метода toArray. Но все еще в силе, так как это просто читать.
PhoneixS

1
применимо к строкам и объектам (по желанию вопроса), но нет метода addAll для основных типов (как целые)
joro

Как описано в этой статье , использование both.toArray(new String[0])будет быстрее both.toArray(new String[both.size()]), даже если это противоречит нашей наивной интуиции. Вот почему так важно измерять реальную производительность при оптимизации. Или просто используйте более простую конструкцию, когда преимущество более сложного варианта не может быть доказано.
Хольгер

42

Решение 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;
}

переработан мой для File [], но это то же самое. Спасибо за ваше решение
ShadowFlame

5
Вероятно, довольно неэффективно, хотя.
JonasCz - Восстановить Монику

Вы можете добавить nullчеки. И, возможно, установите некоторые из ваших переменных в final.
Tripp Kinetics

nullПроверки @TrippKinetics будут скрывать NPE, а не показывать их, и использование final для локальных переменных не имеет никакой пользы (пока).
Мартен Бодевес

1
@Maarten Bodewes Я думаю, вы обнаружите (если вы сравните это, что у меня есть), что for-each работает в то же время, что и индексированный цикл в поздних версиях Java. Оптимизатор позаботится об этом.
дом

33

Я недавно боролся с проблемами с чрезмерным вращением памяти. Если известно, что 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;
}

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


5
это, однако, означает, что вы возвращаете один и тот же массив, и изменение значения в возвращенном массиве изменяет значение в той же позиции, что и возвращенный входной массив.
Лоренцо Боккачча

Да - см. Комментарий в конце моего поста относительно повторного использования массива. Затраты на обслуживание, налагаемые этим решением, в нашем конкретном случае стоили того, но в большинстве случаев, вероятно, следует использовать защитное копирование.
залп

Lorenzo / volley, можете ли вы объяснить, какая часть кода вызывает повторное использование массива? Я думал System.arraycopyкопирует содержимое массива?
Росди Касим

4
Вызывающая сторона обычно ожидает, что вызов concat () вернет вновь выделенный массив. Если a или b равно нулю, concat (), однако, вернет один из переданных в него массивов. Это повторное использование является тем, что может быть неожиданным. (Да, arraycopy выполняет только копирование. Повторное использование происходит при непосредственном возвращении либо a, либо b.)
залп

Код должен быть как можно более понятным. Людям, читающим код, не нужно искать JavaDoc вызываемой функции, чтобы выяснить, что она выполняет одно для одного конкретного условия, а другое - для другого. Короче говоря, вы, как правило, не можете исправить подобные проблемы с комментариями. Простое ifисключение двух утверждений было бы самым простым решением.
Мартен Бодевес

27

Функциональная Java библиотека имеет класс - оболочки массива, экипирование массивов с удобными методами , как конкатенация.

import static fj.data.Array.array;

...а потом

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

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

String[] s = both.array();

27
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));

both.toArray(new String[0]);

3
Ответ велик, но немного сломан. Чтобы сделать его идеальным, вы должны передать toArray () массив нужного вам типа. В приведенном выше примере код должен быть следующим: both.toArray (new String [0]). См .: stackoverflow.com/questions/4042434/…
Ronen Rabinovici

Не знаю, почему этот ответ не оценен выше ... хотя, похоже, ему нужно изменение, предложенное @RonenRabinovici
drmrbrewer

4
Или лучше, без ненужного выделения массива нулевой длины:; both.toArray(new String[both.size()]))
Honza


Привет @ Хонза, можно сделать то же самое, чтобы вернуть массив примитивных целых в 3 строки?
jumping_monkey

18

Еще один способ с Java8 с использованием 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); 
  }

17

Вот адаптация решения silvertab с модифицированными дженериками:

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

ПРИМЕЧАНИЕ. См . Ответ Joachim для решения Java 6. Это не только устраняет предупреждение; это также короче, более эффективно и легче читать!


Вы можете подавить предупреждение для этого метода, но кроме этого, вы ничего не можете сделать. Массивы и дженерики на самом деле не смешиваются.
Дэн Дайер

3
Непроверенное предупреждение может быть устранено, если вы используете Arrays.copyOf (). Смотрите мой ответ для реализации.
Йоахим Зауэр

@SuppressWarnings ("не проверено")
Марк Реноуф

13

Если вы используете этот способ, вам не нужно импортировать какие-либо сторонние классы.

Если вы хотите объединить String

Пример кода для конкатенации двух 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;
    }

Если вы хотите объединить Int

Пример кода для конкатенации двух целочисленных массивов

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

Вот основной метод

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

        }
    }  

Мы можем использовать этот способ также.


11

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

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

Я бы суммировал длину в том же цикле, где вы выполняете нулевую проверку - но это действительно хорошее резюме других ответов здесь. Я считаю, что он даже обрабатывает внутренние типы, такие как «int», не изменяя их на объекты Integer, что на самом деле является ЕДИНСТВЕННОЙ причиной, чтобы обращаться с ними как с массивами, а не просто менять все на ArrayLists. Кроме того, ваш метод может принимать 2 массива и параметр (...), поэтому вызывающий объект знает, что ему нужно передать как минимум два массива, прежде чем он его запустит, и увидит ошибку, но это усложняет циклический код ....
Билл К.

11

Вы можете попробовать преобразовать его в Arraylist и использовать метод addAll, а затем преобразовать обратно в массив.

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

Хорошее решение - было бы лучше, если бы код был подвергнут рефакторингу, чтобы вообще избежать массивов в пользу ArrayLists, но это вне контроля «Ответа» и зависит от спрашивающего.
Билл К

Я считаю, что для работы требуется 4 дополнительных временных объекта.
Дом

@ rghome, по крайней мере, для реализации такой простой задачи не требуется дополнительная библиотека
Фарид

9

Используя потоки Java 8+, вы можете написать следующую функцию:

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

7

Здесь возможна реализация в рабочем коде решения псевдокода, написанного silvertab.

Спасибо 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;
   }
}

Далее следует интерфейс строителя.

Примечание: сборщик необходим, потому что в Java это невозможно сделать

new T[size]

из-за стирания универсального типа:

public interface ArrayBuilderI<T> {

   public T[] build(int size);
}

Вот конкретный конструктор, реализующий интерфейс, строящий Integerмассив:

public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {

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

И, наконец, приложение / тест:

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

7

Это должно быть однострочно.

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

6

Вот Это Да! Здесь много сложных ответов, в том числе простых, которые зависят от внешних зависимостей. как насчет этого:

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

1
..Но неэффективно и медленно.
JonasCz - Восстановить Монику

6

Это работает, но вам нужно вставить свою собственную проверку ошибок.

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

Это, вероятно, не самый эффективный, но он не зависит ни от чего, кроме собственного API Java.


2
+1. Было бы лучше заменить второй forцикл на это:for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
bancer 28.10.10

Используйте, String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)чтобы пропустить первый forцикл. Экономит время, пропорциональное размеру arr1.
Джон Мейер

5

Это преобразованная функция для массива String:

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

5

Как насчет просто

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

И просто делай Array.concat(arr1, arr2). Пока arr1и arr2одного типа, это даст вам другой массив того же типа, содержащий оба массива.


По соображениям производительности я бы предварительно вычислил окончательный размер ArrayList, потому что ArrayList по определению выделяет новый массив и копирует его элементы каждый раз, когда текущий массив заполнен. В противном случае я бы пошел прямо на LinkedList, который не испытывает такой проблемы
usr-local-ΕΨΗΕΛΩΝ

5

Универсальная статическая версия, которая использует высокопроизводительную System.arraycopy, не требуя аннотации @SuppressWarnings:

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

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

4

Вот моя слегка улучшенная версия concatAll Йоахима Зауэра. Он может работать на Java 5 или 6, используя Java 6 System.arraycopy, если он доступен во время выполнения. Этот метод (IMHO) идеально подходит для Android, так как он работает на Android <9 (у которого нет System.arraycopy), но будет по возможности использовать более быстрый метод.

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

1
Хорошая общая идея, но для всех, кто реализует: я бы предпочел версии copyOf и non-copyOf, а не те, которые используют оба способа в качестве отражения.
ректиде

4

Еще один способ задуматься над вопросом. Чтобы объединить два или более массивов, нужно составить список всех элементов каждого массива и затем создать новый массив. Это звучит как создать, List<T>а затем призывает toArrayего. Некоторые другие ответы использует ArrayList, и это нормально. Но как насчет реализации нашего? Это не сложно

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

Я считаю, что вышеупомянутое эквивалентно решениям, которые используют System.arraycopy. Однако я думаю, что у этого есть своя собственная красота.


4

Как насчет :

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

4

Простой вариант, позволяющий объединять более одного массива:

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

3

Используя только собственный API Javas:


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

Теперь этот код не самый эффективный, но он опирается только на стандартные классы Java и прост для понимания. Это работает для любого числа String [] (даже нулевых массивов).


15
Пришлось понизить это за все ненужное создание объекта List.
Программист вне закона
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.