Wydaje się, że nie ma sposobu na rozszerzenie istniejącej tablicy JavaScript o inną tablicę, tj. Na emulację extend
metody Pythona .
Chcę osiągnąć następujące cele:
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
Wiem, że istnieje a.concat(b)
metoda, ale tworzy ona nową tablicę zamiast po prostu rozszerzać pierwszą. Chciałbym algorytm, który działa skutecznie, gdy a
jest znacznie większy niż b
(tj. Taki, który nie kopiuje a
).
Uwaga: To nie jest kopia jak dołączyć coś do tablicy? - celem jest dodanie całej zawartości jednej tablicy do drugiej i zrobienie tego „na miejscu”, tzn. bez kopiowania wszystkich elementów rozszerzonej tablicy.
javascript
arrays
concatenation
DzinX
źródło
źródło
a.push(...b)
. Jest to koncepcja podobna do najwyższej odpowiedzi, ale zaktualizowana do ES6.Odpowiedzi:
.push
Metoda może trwać wiele argumentów. Możesz użyć operatora rozkładania, aby przekazać wszystkie elementy drugiej tablicy jako argumenty do.push
:Jeśli twoja przeglądarka nie obsługuje ECMAScript 6, możesz
.apply
zamiast tego użyć :A może uważasz, że to jest jaśniejsze:
Pamiętaj, że wszystkie te rozwiązania zakończą się niepowodzeniem z błędem przepełnienia stosu, jeśli tablica
b
jest zbyt długa (problemy zaczynają się od około 100 000 elementów, w zależności od przeglądarki).Jeśli nie możesz zagwarantować, że
b
jest wystarczająco krótki, powinieneś użyć standardowej techniki opartej na pętli opisanej w drugiej odpowiedzi.źródło
push
Metoda Array może przyjmować dowolną liczbę argumentów, które są następnie wypychane na tył tablicy. Więca.push('x', 'y', 'z')
jest ważne wezwanie, które rozciągają sięa
od 3 elementów.apply
jest metodą dowolnej funkcji, która pobiera tablicę i używa jej elementów tak, jakby wszystkie zostały podane jawnie jako elementy pozycyjne funkcji. Taka.push.apply(a, ['x', 'y', 'z'])
będzie również rozszerzyć wachlarz przez 3 elementów. Dodatkowoapply
przyjmuje kontekst jako pierwszy argument (przekazujemy goa
ponownie, aby dołączyća
).[].push.apply(a, b)
.Aktualizacja 2018 : Lepszą odpowiedź jest nowsza jeden z kopalni :
a.push(...b)
. Nie głosuj więcej na ten temat, ponieważ tak naprawdę nigdy nie odpowiedział na pytanie, ale był to hack z 2015 roku wokół pierwszego trafienia w Google :)Dla tych, którzy po prostu szukali „Rozszerzenia tablicy JavaScript” i znaleźli się tutaj, możesz bardzo dobrze użyć
Array.concat
.Concat zwróci kopię nowej tablicy, ponieważ początkowy wątek nie chciał. Ale może ci to nie przeszkadzać (z pewnością w przypadku większości zastosowań będzie to w porządku).
Do tego jest też trochę dobrego cukru ECMAScript 6 w postaci operatora spreadu:
(Kopiuje również.)
źródło
arr.push(...arr2)
jest nowsza i lepsza oraz poprawna technicznie odpowiedź na to pytanie.Powinieneś użyć techniki opartej na pętli. Inne odpowiedzi na tej stronie oparte na użyciu
.apply
mogą się nie powieść w przypadku dużych tablic.Dość zwarta implementacja oparta na pętli to:
Następnie możesz wykonać następujące czynności:
Odpowiedź DzinX (przy użyciu push.apply) i inne
.apply
oparte na nim metody zawodzą, gdy tablica, którą dodajemy, jest duża (testy pokazują, że dla mnie duża jest> około 150 000 wpisów w Chrome i> 500 000 wpisów w Firefox). Możesz zobaczyć ten błąd występujący w tym jsperf .Wystąpił błąd, ponieważ rozmiar stosu wywołań został przekroczony, gdy „Function.prototype.apply” jest wywoływany z dużą tablicą jako drugim argumentem. (MDN ma uwagę na temat niebezpieczeństw związanych z przekroczeniem wielkości stosu wywołań przy użyciu Function.prototype.apply - patrz sekcja zatytułowana „Zastosuj i funkcje wbudowane”).
Aby porównać szybkość z innymi odpowiedziami na tej stronie, sprawdź ten jsperf (dzięki EaterOfCode). Implementacja oparta na pętli jest podobna pod względem szybkości do używania
Array.push.apply
, ale zwykle jest nieco wolniejsza niżArray.slice.apply
.Co ciekawe, jeśli dodawana macierz jest rzadka,
forEach
powyższa metoda oparta na rzadkości może skorzystać z rzadkości i przewyższyć.apply
metody oparte; sprawdź ten jsperf, jeśli chcesz to przetestować sam.Nawiasem mówiąc, nie ulegaj pokusie (tak jak ja!) Dalszego skrócenia implementacji forEach do:
ponieważ powoduje to śmieciowe wyniki! Dlaczego? Ponieważ
Array.prototype.forEach
udostępnia trzy argumenty funkcji, którą wywołuje - są to: (element_value, element_index, source_array). Wszystkie zostanąforEach
przekazane do pierwszej tablicy dla każdej iteracji, jeśli użyjesz „forEach (this.push, this)”!źródło
.push.apply
jest w rzeczywistości znacznie szybszy niż.forEach
w wersji 8, najszybsza jest nadal pętla wbudowana..forEach
jest szybsze niż.push.apply
w Chrome / Chromium (we wszystkich wersjach od wersji 25). Nie byłem w stanie przetestować v8 w izolacji, ale jeśli tak, proszę połączyć swoje wyniki. Zobacz jsperf: jsperf.com/array-extending-push-vs-concat/5undefined
, więc.forEach
pomiń je, dzięki czemu będzie najszybszy..splice
jest właściwie najszybszy ?! jsperf.com/array-extending-push-vs-concat/18Najbardziej elegancki wydaje mi się w tych dniach:
Artykuł MDN na temat operatora spreadu wspomina o tym miłym, słodkim sposobie w ES2015 (ES6):
Zauważ, że
arr2
nie może być ogromne (trzymaj poniżej 100 000 przedmiotów), ponieważ stos wywołań przepełnia się, zgodnie z odpowiedzią jcdude.źródło
arr1.push(arr2)
. Może to być taki problem,arr1 = []; arr2=['a', 'b', 'd']; arr1.push(arr2)
że wynikiem jest tablica tablicarr1 == [['a','b','d']]
zamiast dwóch tablic razem. Łatwo jest popełnić błąd. Z tego powodu wolę twoją drugą odpowiedź poniżej. stackoverflow.com/a/31521404/4808079.concat
że drugim argumentem nie może być tablica. Można to osiągnąć przez połączenie operatora spreadu zconcat
, np.arr1.push(...[].concat(arrayOrSingleItem))
Najpierw kilka słów o
apply()
JavaScript, aby zrozumieć, dlaczego go używamy:Push oczekuje listy elementów do dodania do tablicy.
apply()
Sposób przyjmuje jednak oczekiwanych argumentów do połączenia funkcji jako macierzy. To pozwala nam łatwo łączyćpush
elementy jednej tablicy w drugą za pomocą wbudowanejpush()
metody.Wyobraź sobie, że masz te tablice:
i po prostu zrób to:
Wynik będzie:
To samo można zrobić w ES6 za pomocą operatora spreadu („
...
”) w następujący sposób:Krótsze i lepsze, ale obecnie nie w pełni obsługiwane we wszystkich przeglądarkach.
Również jeśli chcesz przenieść wszystko z tablicy
b
doa
, opróżniającb
proces, możesz to zrobić:a wynik będzie następujący:
źródło
while (b.length) { a.push(b.shift()); }
prawda?Jeśli chcesz użyć jQuery, jest $ .merge ()
Przykład:
Wynik: a =
[1, 2, 3, 4, 5]
źródło
jQuery.merge()
?Podoba mi się
a.push.apply(a, b)
metoda opisana powyżej, a jeśli chcesz, zawsze możesz utworzyć funkcję biblioteki w ten sposób:i użyj tego w ten sposób
źródło
Można to zrobić za pomocą
splice()
:Ale chociaż jest brzydszy, nie jest szybszy niż
push.apply
, przynajmniej nie w Firefoksie 3.0.źródło
To rozwiązanie działa dla mnie (przy użyciu operatora rozprzestrzeniania ECMAScript 6):
źródło
Możesz utworzyć polifill dla rozszerzenia, jak mam poniżej. Dodanie do tablicy; w miejscu i zwrócić się, aby można było połączyć inne metody.
źródło
Łączenie odpowiedzi ...
źródło
Kolejne rozwiązanie do połączenia więcej niż dwóch tablic
Następnie zadzwoń i wydrukuj jako:
Dane wyjściowe będą:
Array [1, 2, 3, 4, 5, 6, 7]
źródło
Odpowiedź jest bardzo prosta.
Concat działa bardzo podobnie do konkatenacji ciągów JavaScript. Zwróci kombinację parametru, który umieściłeś w funkcji concat na końcu tablicy, na której wywołujesz funkcję. Najważniejsze jest to, że musisz przypisać zwróconą wartość do zmiennej, aby się zgubiła. Na przykład
źródło
Array.prototype.concat()
MDN , zwróci to nową tablicę , nie będzie ona dołączana do istniejącej tablicy, jak wyraźnie wymagało OP.Użyj
Array.extend
zamiastArray.push
> 150 000 rekordów.źródło
Super prosty, nie liczy na operatorów spreadów ani nie stosuje się, jeśli to jest problem.
Po uruchomieniu kilku testów wydajności jest to bardzo powolne, ale odpowiada na pytanie, czy nie należy tworzyć nowej tablicy. Concat jest znacznie szybszy, nawet jQuery
$.merge()
go wyrzuca.https://jsperf.com/merge-arrays19b/1
źródło
.forEach
zamiast,.map
jeśli nie używasz wartości zwracanej. Lepiej oddaje intencje twojego kodu..map
ale możesz teżb.forEach(function(x) { a.push(x)} )
. W rzeczywistości dodałem to do testu jsperf i jest to włos szybszy niż mapa. Wciąż bardzo wolno..map
tutaj wygląda bardzo dziwnie. To byłoby jak dzwonienieb.filter(x => a.push(x))
. Działa, ale dezorientuje czytelnika, sugerując, że coś się dzieje, gdy tak nie jest..map()
robi i na tym polega problem. Ta wiedza sprawiłaby, że pomyślałem, że potrzebujesz wynikowej tablicy, w przeciwnym razie dobrze byłoby użyć,.forEach()
aby czytelnik był ostrożny w odniesieniu do skutków ubocznych funkcji wywołania zwrotnego. Ściśle mówiąc, twoje rozwiązanie tworzy dodatkową tablicę liczb naturalnych (wynikipush
), podczas gdy pytanie brzmi: „bez tworzenia nowej tablicy”.