Як я можу об'єднати два масиви в 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 (див. Мою відповідь), тому не можна отримати дуже багато чого, маючи єдиний спосіб зробити це. Всі ці дивні та чудові рішення трохи втрачають час.
rghome

Відповіді:


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, недоступні.
kvn

4
Наступний рядок порушить родову частину: concatenate (new String [] {"1"}, new Object [] {new Object ()})
dragon66

Було б непогано використовувати анотацію @SuppressWarnings - я опублікую рішення для цього нижче.
beaudet

+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> тип оператора у своєму класі?
Джоннідеп

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

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
Наскільки це ефективно?
Супухстар

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

3
@Supuhstar: Це, мабуть, не так швидко, як System.arrayCopy. Але і не особливо повільно. Вам, мабуть, доведеться робити це дуже багато разів з величезними масивами в реально чутливих до ефективності контекстах, щоб різниця у часі виконання не мала значення.
Лій

191

Або з коханою Гуавою :

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)

Наскільки я люблю Гуаву, метод від Apache Commons краще справляється з нульовими.
Раві Валлау

7
Хоча добре користуватися бібліотеками, шкода, що проблема була усунена. Тому базове рішення залишається невловимим.
user924272

51
У чому проблема з абстракцією? Не знаю, у чому справа у винаході колеса, якщо ви хочете дізнатися проблему, перевірте джерело чи прочитайте на ньому. Професійний код повинен використовувати бібліотеки високого рівня, набагато краще, якщо він розробляється всередині Google!
Breno Salgado

@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. Швидкий / ефективний. Слід отримати більше оновлень!
Шебла Цама

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 для первинних типів (як ints)
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

@TrippKinetics nullперевірки приховатимуть NPE, а не показувати їх, а використання final для локальних vars не має жодної користі (поки).
Maarten Bodewes

1
@Maarten Bodewes Я думаю, що ви побачите (якщо ви порівняєте його, який я маю), що для-кожного працює в той же час, що і індексований цикл на пізніх версіях Java. Про це піклується оптимізатор.
rghome

33

Нещодавно я боровся з проблемами із надмірним обертанням пам'яті. Якщо а та / або 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, тим самим позбавивши необхідності мати документацію. Але знову ж таки, коли б висловлювання були цілком суть цієї конкретної оптимізації. Я залишу цю відповідь тут, але будьте обережні!


5
це, однак, означає, що ви повертаєте той самий масив і зміна значення повернутого масиву змінює значення в тому самому положенні повернутого масиву, що повертається.
Лоренцо Боккачча

Так - дивіться коментар наприкінці мого повідомлення про повторне використання масиву. Накладне накладне обслуговування, накладене цим рішенням, коштувало цього в нашому конкретному випадку, але оборонне копіювання, мабуть, повинно використовуватися в більшості випадків.
залп

Лоренцо / залп, чи можете ви пояснити, яку частину коду викликають повторне використання масиву? Я думав System.arraycopyкопіює вміст масиву?
Росді Касім

4
Абонент, як правило, очікує дзвінка concat () для повернення щойно виділеного масиву. Якщо або a або b є нульовим, concat () поверне один з масивів, переданих в нього. Це повторне використання може бути несподіваним. (Так, аррейкопія виконує лише копіювання. Повторне використання відбувається безпосередньо після повернення а чи b безпосередньо.)
залп

Код повинен бути максимально зрозумілим. Люди, які читають код, не повинні шукати JavaDoc викликаної функції, щоб дізнатися, що вона робить одне для однієї конкретної умови, а щось інше для іншої. Якщо коротко: ви, як правило, не можете вирішити подібні проблеми дизайну за допомогою коментаря. Просто ifвилучення двох тверджень було б найпростішим виправленням.
Maarten Bodewes

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 (новий рядок [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;
}

ПРИМІТКА. Див . Відповідь Йоахіма щодо рішення 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

Приклад коду для об'єднання двох масивів Integer

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

@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

Використовуйте 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

Ось моя дещо вдосконалена версія конгресу Йоахіма Зауера. Вона може працювати на Java 5 або 6, використовуючи System.arraycopy Java 6, якщо вона доступна під час виконання. Цей метод (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, ніж версію, яка робить обидва шляхом відображення.
rektide

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
Довелося подати заявку на цю непотрібну створення всіх об'єктів списку.
Програматор поза законом
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.