Jaki jest najskuteczniejszy sposób konkatenacji tablic N?

Odpowiedzi:

323

Jeśli łączysz więcej niż dwie tablice, concat()jest to droga do wygody i prawdopodobnej wydajności.

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

W celu połączenia tylko dwóch tablic pushmożna użyć zamiast tego wielu argumentów składających się z elementów do dodania do tablicy, aby dodać elementy z jednej tablicy do końca drugiej bez tworzenia nowej tablicy. Dzięki slice()niemu można go również użyć zamiast, concat()ale wydaje się, że nie ma żadnej przewagi wydajności .

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

W ECMAScript 2015 i nowszych wersjach można to jeszcze bardziej zmniejszyć

a.push(...b)

Wydaje się jednak, że w przypadku dużych tablic (rzędu 100 000 lub więcej elementów) technika przekazywania tablicy elementów do push(przy użyciu apply()lub operatora rozprzestrzeniania ECMAScript 2015) może się nie powieść. W przypadku takich tablic lepszym rozwiązaniem jest użycie pętli. Szczegółowe informacje można znaleźć na stronie https://stackoverflow.com/a/17368101/96100 .

Tim Down
źródło
1
a.concat(b)Wydaje mi się, że twój test może zawierać błąd: przypadek testowy wydaje się niepotrzebnie robić kopię tablicy, aa następnie ją wyrzucać.
ninjagecko
1
@ninjagecko: Masz rację. Zaktualizowałem go: jsperf.com/concatperftest/6 . W szczególnym przypadku tworzenia nowej tablicy, która łączy dwie istniejące tablice, wydaje się, że jest concat()ona ogólnie szybsza. W przypadku konkatenacji tablicy z istniejącą tablicą w miejscu, push()jest droga. Zaktualizowałem swoją odpowiedź.
Tim Down
16
Mogę zaświadczyć, że rozszerzenie pojedynczej tablicy o kilka nowych tablic przy użyciu metody push.apply zapewnia ogromną przewagę wydajności (~ 100x) w porównaniu z prostym wywołaniem konkat. Mam do czynienia z bardzo długimi listami krótkich list liczb całkowitych w v8 / node.js.
chbrown
1
Jeszcze bardziej zwięzłym sposobem jest a.push (... b);
dinvlad
1
@dinvlad: Prawda, ale tylko w środowiskach ES6. Do mojej odpowiedzi dodałem notatkę.
Tim Down
158
[].concat.apply([], [array1, array2, ...])

edycja : dowód wydajności: http://jsperf.com/multi-array-concat/7

edit2 : Tim Supinie wspomina w komentarzach, że może to spowodować, że interpreter przekroczy rozmiar stosu wywołań. Być może zależy to od silnika js, ale dostałem również „Przekroczono maksymalny rozmiar stosu wywołań” przynajmniej w Chrome. Przypadek testowy: [].concat.apply([], Array(300000).fill().map(_=>[1,2,3])). (Otrzymałem również ten sam błąd przy użyciu obecnie akceptowanej odpowiedzi, więc ktoś przewiduje takie przypadki użycia lub buduje bibliotekę dla innych, specjalne testy mogą być konieczne bez względu na wybrane rozwiązanie).

ninjagecko
źródło
3
@ c69: wydaje się być tak samo skuteczny, jak wybrana odpowiedź wielokrotnie .push (#, #, ..., #), przynajmniej w Chrome. jsperf.com/multi-array-concat Wybrana odpowiedź przez Tim Down może również zawierać błąd. Ten link jest porównaniem wydajności łączenia wielu tablic jako zadane pytanie (nie tylko 2); testowanych jest wiele możliwych długości.
ninjagecko
IMO to najskuteczniejszy sposób na „scalenie” tablic, dobra robota
Eric Uldall,
Ta odpowiedź jest szczególnie przydatna, gdy N nie jest znane z góry, na przykład gdy masz tablicę o dowolnej długości i chcesz je wszystkie połączyć.
jfriend00
3
Z ES6 i operatorami rozprzestrzeniania staje się jeszcze prostsze: [] .concat (... [array1, array2, ...]) Cóż, drugie trzy kropki są trochę niefortunne. Pierwsze trzy to operator rozprzestrzeniania developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Eydrian
Eydrian: Osobiście staram się unikać operatora rozprzestrzeniania, ponieważ jest on bardzo nieefektywny, ale nie jestem jeszcze pewien, czy to dlatego, że implementacja jest niedojrzała, czy semantyka specyfikacji es6 wymaga nieco cięższego podnoszenia (tj. Nigdy nie będzie lepsza ). Nie uruchomiłem żadnych testów porównawczych w tym konkretnym przypadku.
ninjagecko
34

Dla osób używających ES2015 (ES6)

Możesz teraz używać składni spreadu do łączenia tablic:

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]
Duncan Luk
źródło
Jak to jest wydajne? Z tego, co przetestowałem, jest to bardzo wolne w przypadku tablic zawierających obiekty, patrz: jsperf.com/array-concat-vs-array-push-vs-array-spread/1
hitautodestruct
28

Ta concat()metoda służy do łączenia dwóch lub więcej tablic. Nie zmienia istniejących tablic, zwraca tylko kopię połączonych tablic.

array1 = array1.concat(array2, array3, array4, ..., arrayN);
dogbane
źródło
1
Czasami nienawidzę JavaScript za brak modyfikacji oryginalnej tablicy. 🙄
Vincent Hoch-Drei,
@ VincentHoch-Drei concatjest specjalnie używany do tworzenia nowych tablic bez mutowania oryginalnej tablicy. Jeśli chcesz zaktualizować array1, musisz użyćarray1.push(...array2, ...array3, ...array4)
adiga
24

Użyj Array.prototype.concat.apply do obsługi konkatenacji wielu tablic:

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

Przykład:

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
źródło
1
Podoba mi się ten! Działa z łatwością ze zmienną liczbą tablic do łączenia. +1
Joel
14

Jeśli jesteś w trakcie przepuszczania wyniku przez mapę / filtr / sortowanie itp. I chcesz skonkatować tablicę tablic, możesz użyć 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
źródło
14

W przypadku tablicy wielu tablic i ES6 użyj

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

Na przykład:

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 ]
David
źródło
1
Ponadto można usunąć zduplikowane elementy za pomocą newArr = Array.from(new Set(newArr));.
Darius M.
Dlaczego w maszynopisie to się dzieje any[]? Pisanie jest tam - dziwne.
Simon_Weaver,
Jest to naprawdę okropnie nieefektywne przy większych woluminach tablic. jsperf.com/flatten-array-203948 [].concat.apply([], ...arr) działa znacznie lepiej na dużych woluminach.
colemars,
7

Teraz możemy łączyć wiele tablic za pomocą ES6 Spread. Zamiast używać concat()do konkatenacji tablic, spróbuj użyć składni rozproszonej, aby połączyć wiele tablic w jedną spłaszczoną tablicę. na przykład:

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
źródło
5

rozwiązane w ten sposób.

let arr = [[1, 2], [3, 4], [5, 6]];
 console.log([].concat(...arr));
Th1
źródło
Idealne rozwiązanie.
nehem
4

Możesz użyć strony jsperf.com do porównania wydajności. Oto link do konkat .

Dodano porównanie między:

var c = a.concat(b);

i:

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

Drugi jest prawie 10 razy wolniejszy w chromie.

gor
źródło
Możesz jednak użyć tego push.apply(), co wydaje się być szybsze niż concat()we wszystkich przeglądarkach oprócz Chrome. Zobacz moją odpowiedź.
Tim Down
3

Oto funkcja, dzięki której można połączyć wiele tablic

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

    return newArr;
}

Przykład -

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

wyjdzie

[1,2,3,5,2,1,4,2,8,9]
Koushik Das
źródło
2

Jeśli masz tablicę tablic i chcesz połączyć elementy w jedną tablicę, wypróbuj następujący kod (wymaga 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];

Lub jeśli lubisz programowanie funkcjonalne

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

Lub jeszcze lepiej ze składnią ES5, bez operatora spreadu

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

Ten sposób jest przydatny, jeśli nie znasz nie. tablic w czasie kodowania.

Nowicjusz
źródło
2

Skróć za pomocą ES6.

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

Powoduje to konkatację i unikalność wielu tablic;

Demo na codepen

ronaldtgi
źródło
robi, ale usuwa duplikaty .. co zrobić, jeśli nie chcę usuwać duplikatów tablic?
Krunal Shah
new Set()usuwa zduplikowane elementy. Po prostu to usuń. [].concat(...Array)
ronaldtgi
Chcę użyć nowego zestawu ([]. concat (... Array)); ale chcę też usunąć duplikaty wraz z nim w jednym wyrażeniu. Czy to możliwe ?
Krunal Shah
2

Scal tablicę za pomocą push:

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

Korzystanie z operatora Concat and 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);

Zobia Kanwal
źródło
1

gdzie „n” to pewna liczba tablic, może tablica tablic. . .

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

rashadb
źródło
0

Spróbuj tego:

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

i=i.concat(j);
JAiro
źródło
@reggie, oboje skopiowaliście z tego samego źródła;)
I.devries
nie, mam informacje w tym samym linku, co ty. ilovethecode.com/Javascript/Javascript-Tutorials-How_To-Easy/...
Jairo
tak ... Chyba mamy to z tego samego źródła: D
reggie
przynajmniej @JAiro zmieniło zawartość tablicy. @reggie nie. :)
dogbane
to samo, ważne jest, aby pomóc ludziom rozwiązać jego problemy :)
JAiro
0

jeśli tablice N są pobierane z bazy danych i nie są zakodowane na stałe, zrobię to w ten sposób za pomocą ES6

let get_fruits = [...get_fruits , ...DBContent.fruit];
Akinnifesi Damilola
źródło