Каков наиболее эффективный способ объединения N массивов?

Ответы:

323

Если вы объединяете более двух массивов, concat()это путь для удобства и вероятной производительности.

var a = [1, 2], b = ["x", "y"], c = [true, false];
var d = a.concat(b, c);
console.log(d); // [1, 2, "x", "y", true, false];

Для объединения только двух массивов можно использовать тот факт, что pushдля добавления в массив можно использовать несколько аргументов, состоящих из элементов, добавляемых в массив, без создания нового массива. С slice()ним также можно использовать вместо, concat()но, как представляется, это не дает никакого преимущества в производительности .

var a = [1, 2], b = ["x", "y"];
a.push.apply(a, b);
console.log(a); // [1, 2, "x", "y"];

В ECMAScript 2015 и более поздних версиях это можно уменьшить еще больше до

a.push(...b)

Однако, похоже, что для больших массивов (порядка 100 000 членов или более) метод передачи массива элементов push(с использованием apply()или оператора распространения ECMAScript 2015) может дать сбой. Для таких массивов лучше использовать цикл. См. Https://stackoverflow.com/a/17368101/96100 для получения подробной информации.

Тим Даун
источник
1
Я полагаю, что в вашем тесте может быть ошибка: a.concat(b)контрольный пример, кажется, напрасно делает копию массива, а aзатем выбрасывает его.
ninjagecko
1
@ninjagecko: Ты прав. Я обновил его: jsperf.com/concatperftest/6 . В конкретном случае создания нового массива, объединяющего два существующих массива, concat()обычно это происходит быстрее. Для случая объединения массива в существующий массив на месте, push()это путь. Я обновил свой ответ.
Тим Даун
16
Я могу засвидетельствовать, что расширение одного массива несколькими новыми массивами с помощью метода push.apply дает огромное преимущество в производительности (~ 100x) по сравнению с простым вызовом concat. Я имею дело с очень длинными списками коротких списков целых чисел, в v8 / node.js.
2012 года
1
Еще более краткий способ - это a.push (... b);
dinvlad
1
@dinvlad: правда, но только в среде ES6. Я добавил примечание к своему ответу.
Тим Даун
158
[].concat.apply([], [array1, array2, ...])

редактировать : доказательство эффективности: http://jsperf.com/multi-array-concat/7

edit2 : Тим Супини упоминает в комментариях, что это может привести к тому, что интерпретатор превысит размер стека вызовов. Возможно, это зависит от движка js, но я также получил "Максимальный размер стека вызовов превышен" по крайней мере в Chrome. Тестовый пример: [].concat.apply([], Array(300000).fill().map(_=>[1,2,3])). (Я также получил ту же ошибку при использовании принятого в настоящее время ответа, поэтому можно ожидать таких случаев использования или создавать библиотеку для других, поэтому может потребоваться специальное тестирование независимо от того, какое решение вы выберете.)

ninjagecko
источник
3
@ c69: он выглядит примерно так же эффективно, как и выбранный ответ многократно .push (#, #, ..., #), по крайней мере, в Chrome. jsperf.com/multi-array-concat В выбранном ответе Тима Дауна также может быть ошибка. Эта ссылка представляет собой сравнение производительности объединения нескольких массивов в качестве задаваемого вопроса (не только 2); несколько возможных длин проверяются.
ninjagecko
ИМО, это самый эффективный способ «слияния» n массивов, молодец
Эрик Улдолл
Этот ответ особенно полезен, когда N неизвестно заранее, например, когда у вас есть массив массивов произвольной длины, и вы хотите, чтобы они все были объединены.
Jfriend00
3
С ES6 и операторами распространения это становится еще проще: [] .concat (... [array1, array2, ...]) Что ж, вторые три точки немного неудачны. Первые три является распространение оператора developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
Eydrian
Эйдриан: Я лично стараюсь избегать оператора распространения, потому что он очень неэффективен, но я пока не уверен, является ли это реализацией незрелой, или семантика спецификации es6 требует более тяжелого поднятия (то есть никогда не станет лучше ). Однако в этом конкретном случае никаких тестов не проводилось.
ninjagecko
34

Для людей, использующих ES2015 (ES6)

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

const arr1 = [0, 1, 2],
      arr2 = [3, 4, 5];

const result1 = [...arr1, ...arr2]; // -> [0, 1, 2, 3, 4, 5]

// or...

const result2 = [...arr2, ...arr1]; // -> [3, 4, 5, 0, 1, 2]
Дункан Лук
источник
Насколько это эффективно? Из того, что я тестировал, это очень медленно для массивов, содержащих объекты, см .: jsperf.com/array-concat-vs-array-push-vs-array-spread/1
hitautodestruct,
28

concat()Метод используется для соединения двух или более массивов. Он не изменяет существующие массивы, он только возвращает копию объединенных массивов.

array1 = array1.concat(array2, array3, array4, ..., arrayN);
кендырь
источник
1
Иногда я ненавижу JavaScript за то, что он не изменяет исходный массив. V
Винсент Хох-Драй
@ VincentHoch-Drei concatспециально используется для создания новых массивов без изменения исходного массива. Если вы хотите обновить array1, вы должны будете использоватьarray1.push(...array2, ...array3, ...array4)
adiga
24

Используйте Array.prototype.concat.apply для обработки конкатенации нескольких массивов:

var resultArray = Array.prototype.concat.apply([], arrayOfArraysToConcat);

Пример:

var a1 = [1, 2, 3],
    a2 = [4, 5],
    a3 = [6, 7, 8, 9];
Array.prototype.concat.apply([], [a1, a2, a3]); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Burnee
источник
1
Мне нравится этот! Работает легко с переменным числом массивов для объединения. +1
Джоэл
14

Если вы находитесь в процессе передачи результата через карту / фильтр / сортировку и т. Д. И хотите объединить массив массивов, вы можете использовать reduce

let sorted_nums = ['1,3', '4,2']
  .map(item => item.split(','))   // [['1', '3'], ['4', '2']]
  .reduce((a, b) => a.concat(b))  // ['1', '3', '4', '2']
  .sort()                         // ['1', '2', '3', '4']
artnikpro
источник
14

Для массива из нескольких массивов и ES6 используйте

Array.prototype.concat(...arr);

Например:

const arr = [[1, 2, 3], [4, 5, 6], [7, 8 ,9]];
const newArr = Array.prototype.concat(...arr);
// output: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Дэвид
источник
1
Кроме того, вы можете удалить дубликаты элементов с помощью newArr = Array.from(new Set(newArr));.
Дариус М.
Почему в машинописи это становится any[]? Печатание там - странно.
Simon_Weaver
Это на самом деле довольно ужасно неэффективно при больших объемах массива. jsperf.com/flatten-array-203948 [].concat.apply([], ...arr) работает значительно лучше на больших объемах.
Colemars
7

Теперь мы можем объединить несколько массивов, используя ES6 Spread. Вместо того, concat()чтобы использовать для объединения массивов, попробуйте использовать синтаксис расширения, чтобы объединить несколько массивов в один плоский массив. например:

var a = [1,2];
var b = [3,4];
var c = [5,6,7];
var d = [...a, ...b, ...c];
// resulting array will be like d = [1,2,3,4,5,6,7]
chinmayan
источник
5

решено так

let arr = [[1, 2], [3, 4], [5, 6]];
 console.log([].concat(...arr));
Th1
источник
Идеальное решение.
Нехем
4

Вы можете использовать сайт jsperf.com для сравнения производительности. Вот ссылка на Конкат .

Добавлено сравнение между:

var c = a.concat(b);

и:

var c = [];
for (i = 0; i < a.length; i++) {
    c.push(a[i]);
}
for (j = 0; j < b.length; j++) {
    c.push(b[j]);
}

Второй почти в 10 раз медленнее хрома.

Gor
источник
Тем не менее, вы можете использовать push.apply(), что, кажется, быстрее, чем concat()во всех браузерах, кроме Chrome. Смотри мой ответ.
Тим Даун
4

Легко с функцией concat:

var a = [1,2,3];
var b = [2,3,4];
a = a.concat(b);
>> [1,2,3,2,3,4]
Дмитрий Фарков
источник
Пожалуйста, имейте в виду, что этот метод очень неэффективен, к сожалению, jsperf.com/concat-small-arrays-vs-push-vs-loop
Дан,
3

Вот функция, с помощью которой вы можете объединить несколько массивов

function concatNarrays(args) {
    args = Array.prototype.slice.call(arguments);
    var newArr = args.reduce( function(prev, next) {
       return prev.concat(next) ;
    });

    return newArr;
}

Пример -

console.log(concatNarrays([1, 2, 3], [5, 2, 1, 4], [2,8,9]));

будет выводить

[1,2,3,5,2,1,4,2,8,9]
Кушик дас
источник
3

Объединить массив с Push:

const array1 = [2, 7, 4];
const array2 = [3, 5,9];
array1.push(...array2);
console.log(array1)

Использование оператора Concat и Spread:

const array1 = [1,2];
const array2 = [3,4];

// Method 1: Concat 
const combined1 = [].concat(array1, array2);

// Method 2: Spread
const combined2 = [...array1, ...array2];

console.log(combined1);
console.log(combined2);

Зобия Канвал
источник
2

Если у вас есть массив массивов и вы хотите объединить элементы в один массив, попробуйте следующий код (требуется ES2015):

let arrOfArr = [[1,2,3,4],[5,6,7,8]];
let newArr = [];
for (let arr of arrOfArr) {
    newArr.push(...arr);
}

console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

Или если вы в функциональном программировании

let arrOfArr = [[1,2,3,4],[5,6,7,8]];
let newArr = arrOfArr.reduce((result,current)=>{
    result.push(...current);
    return result;
});

console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

Или даже лучше с синтаксисом ES5, без оператора распространения

var arrOfArr = [[1,2,3,4],[5,6,7,8]];
var newArr = arrOfArr.reduce((result,current)=>{
    return result.concat(current);
});
console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

Этот способ удобен, если вы не знаете, нет. массивов во время кода.

новичек
источник
2

Укоротить с ES6.

new Set([].concat(...Array));

Это делает конкат и уникальным множественные массивы;

Демо на коде

ronaldtgi
источник
это делает, но это удаляет дубликаты .. что делать, если я не хочу удалять дублирующиеся массивы?
Крунал Шах
new Set()удаляет дубликаты Просто удали это. [].concat(...Array)
Роналдтги
я хочу использовать новый Set ([]. concat (... Array)); но я также хочу удалить дубликаты вместе с ним в одном выражении. Является ли это возможным ?
Крунал Шах
1

где 'n' - это некоторое количество массивов, возможно, массив массивов. , ,

var answer = _.reduce (n, function (a, b) {return a.concat (b)})

rashadb
источник
1

Если есть только два массива для объединения, и вам действительно нужно добавить один из массивов, а не создавать новый, путь или цикл - это путь.

Тест: https://jsperf.com/concat-small-arrays-vs-push-vs-loop/

Дэн
источник
0

попробуй это:

i=new Array("aaaa", "bbbb");
j=new Array("cccc", "dddd");

i=i.concat(j);
Хайро
источник
@reggie, вы оба скопированы из одного источника;)
I.devries
Нет, я должен проверить информацию в той же ссылке, что и вы. ilovethecode.com/Javascript/Javascript-Tutorials-How_To-Easy/…
JAiro
да ... я думаю, что мы получили его из того же источника: D
Реджи
по крайней мере @JAiro изменил содержимое массива. @reggie не сделал. :)
Dogbane
это то же самое, главное, помочь людям решить свои проблемы :)
JAiro
0

если N-массивы получены из базы данных, а не жестко закодированы, я сделаю это, используя ES6

let get_fruits = [...get_fruits , ...DBContent.fruit];
Акиннифеси Дамилола
источник