Який найефективніший спосіб об'єднати N масивів?


251

Який найефективніший спосіб об'єднати N масивів об’єктів у JavaScript?

Масиви є змінними, і результат може бути збережений в одному з вхідних масивів.


Відповіді:


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

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


3
@ c69: це здається настільки ж ефективним, як обрана відповідь неодноразово .push (#, #, ..., #), принаймні, у Chrome. jsperf.com/multi-array-concat Обрана Тім Дауном відповідь також може мати помилку. Це посилання є порівнянням продуктивності приєднання до декількох масивів як заданого питання (а не лише 2); тестуються кілька можливих довжин.
ninjagecko

IMO - це найефективніший спосіб "злити" 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 за те, щоб не змінити початковий масив. 🙄
Вінсент Хох-

@ 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]

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']

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) набагато краще в великих обсягах.
колемари

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]

5

вирішено так.

let arr = [[1, 2], [3, 4], [5, 6]];
 console.log([].concat(...arr));

Ідеальне рішення.
nehem

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 разів повільніше хромований.


Однак ви можете використовувати push.apply(), що здається швидше, ніж concat()у всіх браузерах, крім Chrome. Дивіться мою відповідь.
Тім Даун


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]

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

Це робить стислим і унікальним кілька масивів;

Демо на кодені


це робить, але видаляє дублікати .. що робити, якщо я не хочу видалити дублікати масивів?
Крунал Шах

new Set()видаляє повторювані елементи. Просто видаліть його. [].concat(...Array)
ronaldtgi

я хочу використовувати новий Set ([]. concat (... масив)); але я також хочу видалити дублікати разом з ним в одному виразі. Це можливо ?
Крунал Шах

2

Об’єднати масив із натисканням:

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


1

де 'n' - деяка кількість масивів, можливо, масив масивів. . .

var відповідь = _.reduce (n, функція (a, b) {return a.concat (b)})



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