Wypychanie elementów tablicy do innej tablicy

Mam tablicę JavaScript dataArray którą chcę wepchnąć do nowej tablicy newArray. Tylko, że nie chcę newArray[0] Być dataArray. Chcę wcisnąć wszystkie elementy do nowej tablicy:

var newArray = [];

newArray.pushValues(dataArray1);
newArray.pushValues(dataArray2);
// ...

Albo nawet lepiej:

var newArray = new Array (
   dataArray1.values(),
   dataArray2.values(),
   // ... where values() (or something equivalent) would push the individual values into the array, rather than the array itself
);

Więc teraz nowa tablica zawiera wszystkie wartości poszczególnych tablic danych. Czy są dostępne jakieś skróty typu pushValues, żebym nie musiał iterować nad każdym pojedynczym dataArray, dodając elementy jeden po drugim?

Author: Alexander Abakumov, 2010-11-11

15 answers

Użyj funkcji concat , Tak:

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayA.concat(arrayB);

Wartość newArray będzie [1, 2, 3, 4] (arrayA i arrayB pozostają bez zmian; concat tworzy i zwraca nową tablicę dla wyniku).

 913
Author: WiseGuyEh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-22 18:15:19

Pod warunkiem, że Twoje tablice nie są duże (patrz zastrzeżenie poniżej), możesz użyć metody push() tablicy, do której chcesz dołączyć wartości. {[5] } może pobierać wiele parametrów, więc możesz użyć jego metody apply(), aby przekazać tablicę wartości do wypchnięcia jako listę parametrów funkcji. Ma to przewagę nad używaniem concat() dodawania elementów do tablicy zamiast tworzenia nowej tablicy.

Wydaje się jednak, że dla dużych tablic (rzędu 100 000 członków lub więcej), ta sztuczka może się nie udać. Dla takich tablic lepszym podejściem jest użycie pętli. Zobacz https://stackoverflow.com/a/17368101/96100 Po szczegóły.

var newArray = [];
newArray.push.apply(newArray, dataArray1);
newArray.push.apply(newArray, dataArray2);

Możesz uogólnić to na funkcję:

function pushArray(arr, arr2) {
    arr.push.apply(arr, arr2);
}

... lub dodać go do prototypu Array:

Array.prototype.pushArray = function(arr) {
    this.push.apply(this, arr);
};

var newArray = [];
newArray.pushArray(dataArray1);
newArray.pushArray(dataArray2);

... lub emulować oryginalną metodę push(), pozwalając na wiele parametrów używając faktu, że concat(), podobnie jak push(), pozwala na wiele parametrów:

Array.prototype.pushArray = function() {
    this.push.apply(this, this.concat.apply([], arguments));
};

var newArray = [];
newArray.pushArray(dataArray1, dataArray2);

Oto wersja oparta na pętli ostatni przykład, odpowiedni dla dużych tablic i wszystkich głównych przeglądarek, w tym IE

Array.prototype.pushArray = function() {
    var toPush = this.concat.apply([], arguments);
    for (var i = 0, len = toPush.length; i < len; ++i) {
        this.push(toPush[i]);
    }
};
 595
Author: Tim Down,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32

Dodam jeszcze jedną" przyszłościową " odpowiedź

W ECMAScript 6 możesz użyć operatora spreadu:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);

Operator spreadu nie jest jeszcze uwzględniony we wszystkich głównych przeglądarkach. Aktualna zgodność znajduje się w tej (stale aktualizowanej) tabeli zgodności .

Można jednak użyć operatora spreadu z Babel.js .

Edit:

Zobacz odpowiedź Jacka Giffina poniżej, aby uzyskać więcej komentarzy na temat wydajności. Wygląda na to, że concat jest jeszcze lepszy i szybszy niż operator spreadu.

 239
Author: Karel Bílek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-17 05:47:22

Znalazł elegancki sposób z MDN

var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];

// Merge the second array into the first one
// Equivalent to vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']

Lub możesz użyć spread operator funkcji ES6:

let fruits = [ 'apple', 'banana'];
const moreFruits = [ 'orange', 'plum' ];

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]
 128
Author: Believe2014,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-09 16:18:06
var a=new Array('a','b','c');
var b=new Array('d','e','f');
var d=new Array('x','y','z');
var c=a.concat(b,d)
Czy to rozwiązuje twój problem ?
 11
Author: Sébastien VINCENT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-11 15:37:14

Następujące wydaje mi się najprostsze:

var newArray = dataArray1.slice();
newArray.push.apply(newArray, dataArray2);

Ponieważ "push" pobiera zmienną liczbę argumentów, możesz użyć metody apply funkcji push do wypchnięcia wszystkich elementów innej tablicy. Konstruuje wywołanie push używając pierwszego argumentu ("newArray" tutaj) jako "this" I elementy tablicy jako pozostałe argumenty.

slice w pierwszym poleceniu otrzymuje kopię pierwszej tablicy, więc nie można jej modyfikować.

Update Jeśli używasz wersja javascript z slice dostępna, można uprościć wyrażenie push do:

newArray.push(...dataArray2)
 10
Author: shaunc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-19 13:58:27

Istnieje wiele odpowiedzi mówiących o tablicy.prototyp.przyj.Zastosuj . Oto jasny przykład:

var dataArray1 = [1, 2];
var dataArray2 = [3, 4, 5];
var newArray = [ ];
Array.prototype.push.apply(newArray, dataArray1); // newArray = [1, 2]
Array.prototype.push.apply(newArray, dataArray2); // newArray = [1, 2, 3, 4, 5]
console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5]

Jeśli masz składnię ES6:

var dataArray1 = [1, 2];
var dataArray2 = [3, 4, 5];
var newArray = [ ];
newArray.push(...dataArray1); // newArray = [1, 2]
newArray.push(...dataArray2); // newArray = [1, 2, 3, 4, 5]
console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5]
 8
Author: Stephen Quan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-23 01:14:42

Z JavaScript ES6, można użyć ... operator jako operator spreadu, który zasadniczo przekształci tablicę na wartości. Następnie możesz zrobić coś takiego:

var myArray = [1,2,3,4,5];
var moreData = [6,7,8,9,10];

myArray = [
  ...myArray,
  ...moreData,
];

Chociaż składnia jest zwięzła, Nie wiem, jak to działa wewnętrznie i jakie są implikacje wydajności dla dużych tablic.

 6
Author: Ryan H.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-29 18:24:56

Poniższa funkcja nie ma problemu z długością tablic i działa lepiej niż wszystkie sugerowane rozwiązania:

function pushArray(list, other) {
    var len = other.length;
    var start = list.length;
    list.length = start + len;
    for (var i = 0; i < len; i++ , start++) {
        list[start] = other[i];
    }
}

Niestety, jspref odmawia przyjęcia moich zgłoszeń, więc tutaj są wyniki za pomocą benchmark.js

        Name            |   ops/sec   |  ± %  | runs sampled
for loop and push       |      177506 |  0.92 | 63
Push Apply              |      234280 |  0.77 | 66
spread operator         |      259725 |  0.40 | 67
set length and for loop |      284223 |  0.41 | 66

Gdzie

Dla loop i push to:

    for (var i = 0, l = source.length; i < l; i++) {
        target.push(source[i]);
    }

Push Apply:

target.push.apply(target, source);

Operator spreadu:

    target.push(...source);

I wreszcie 'set length and for loop' jest powyższą funkcją

 6
Author: Panos Theof,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-20 15:01:39

Oto sposób ES6

var newArray = [];
let dataArray1 = [1,2,3,4]
let dataArray2 = [5,6,7,8]
newArray = [...dataArray1, ...dataArray2]
console.log(newArray)
 2
Author: Black Mamba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-15 05:10:57

Badania I Wyniki

Dla Faktów, test wydajności w jsperf i sprawdzanie niektórych rzeczy w konsoli są wykonywane. Do badań strona irt.org jest używany. Poniżej znajduje się zbiór wszystkich tych źródeł razem Plus przykładowa funkcja na dole.

╔═══════════════╦══════╦═════════════════╦═══════════════╦═════════╦══════════╗
║ Method        ║Concat║slice&push.apply ║ push.apply x2 ║ ForLoop ║Spread    ║
╠═══════════════╬══════╬═════════════════╬═══════════════╬═════════╬══════════╣
║ mOps/Sec      ║179   ║104              ║ 76            ║ 81      ║28        ║
╠═══════════════╬══════╬═════════════════╬═══════════════╬═════════╬══════════╣
║ Sparse arrays ║YES!  ║Only the sliced  ║ no            ║ Maybe2	 ║no        ║
║ kept sparse   ║      ║array (1st arg)  ║               ║         ║          ║
╠═══════════════╬══════╬═════════════════╬═══════════════╬═════════╬══════════╣
║ Support       ║MSIE 4║MSIE 5.5         ║ MSIE 5.5      ║ MSIE 4  ║Edge 12   ║
║ (source)      ║NNav 4║NNav 4.06        ║ NNav 4.06     ║ NNav 3  ║MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬═══════════════╬═════════╬══════════╣
║Array-like acts║no    ║Only the pushed  ║ YES!          ║ YES!    ║If have   ║
║like an array  ║      ║array (2nd arg)  ║               ║         ║iterator1	║
╚═══════════════╩══════╩═════════════════╩═══════════════╩═════════╩══════════╝
1 If the array-like object does not have a Symbol.iterator property, then trying
  to spread it will throw an exception.
2 Depends on the code. The following example code "YES" preserves sparseness.
function mergeCopyTogether(inputOne, inputTwo){
    var oneLen = inputOne.length, twoLen = inputTwo.length;
    var newArr = [], newLen = newArr.length = oneLen + twoLen;
    for (var i=0, tmp; i !== oneLen; ++i) {
        tmp = inputOne[i];
        if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
    }
    for (var i=0, tmp; i !== oneLen; ++i) {
        tmp = inputOne[i];
        if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
    }
    return newArr;
}

Jak widać powyżej, argumentowałbym, że Concat jest prawie zawsze drogą zarówno dla wydajności, jak i zdolności do zachowania Rzadkości zapasowych tablic. Wtedy dla array-likes (np. DOMNodeLists like document.body.children), zalecałbym użycie pętli for, ponieważ jest to zarówno 2. Najbardziej wydajna, jak i jedyna inna metoda, która zachowuje rzadkie tablice. Poniżej szybko przejdziemy do tego, co rozumie się przez rzadkie tablice i array-likes, aby wyjaśnić zamieszanie.

Przyszłość

Na początku niektórzy ludzie mogą pomyśleć, że jest to Fuks i że dostawcy przeglądarek w końcu przejdą do optymalizacji tablicy.prototyp.push to be fast enough to beat / Align = "left" / prototyp.konkat. Źle! / Align = "left" / prototyp.concat zawsze będzie szybszy (przynajmniej w zasadzie), ponieważ jest prostym copy-n-paste nad danymi. Poniżej znajduje się uproszczony diagram perswado-wizualny, jak może wyglądać implementacja tablicy 32-bitowej (proszę zauważyć, że rzeczywiste implementacje są o wiele bardziej skomplikowane)

Byte ║ Data here
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int length = 0x00000001
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueIndex = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (or whereever it is in memory)
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid

Jak widać powyżej, wszystko, co musisz zrobić, aby skopiować coś takiego, jest prawie tak proste, jak skopiowanie bajtu za bajt. Z Tablicą.prototyp.przyj.zastosuj, to o wiele więcej niż prosty copy-n-paste nad danymi. ".apply " musi sprawdzić każdy indeks w tablicy i przekonwertować go na zestaw argumentów przed przekazaniem go do tablicy.prototyp.przyj. / Align = "Left" / prototyp.push musi dodatkowo przydzielić więcej pamięci za każdym razem, a (w przypadku niektórych implementacji przeglądarki) może nawet przeliczać dane wyszukiwania pozycji pod kątem Rzadkości.

Alternatywnym sposobem myślenia o tym jest to. Tablica źródłowa pierwsza to duży stos papierów zszytych razem. Tablica źródłowa druga to także kolejny duży stos papierów. Czy byłoby szybciej dla ciebie

  1. idź do sklepu, kup papier potrzebny na kopię każdej tablicy źródłowej. Następnie umieść stosy tablic źródłowych papieru w kopiarce i zszywaj powstałe dwie kopie razem.
  2. idź do sklepu, kup papier na jedną kopię pierwszej tablicy źródłowej. Następnie ręcznie skopiuj tablicę źródłową do nowego papieru, upewniając się, że wypełnisz wszelkie puste, rzadkie miejsca. Potem wróć do sklepu, kup wystarczy papieru na drugą tablicę źródłową. Następnie przejdź przez drugą tablicę źródłową i skopiuj ją, upewniając się, że nie ma pustych luk w kopii. Następnie zszyj wszystkie skopiowane papiery.

W powyższej analogii, opcja # 1 reprezentuje tablicę.prototyp.concat while #2 reprezentuje tablicę.prototyp.przyj.aplikuj. Przetestujmy to z podobnym JSperf różniącym się tylko tym, że ten testuje metody na rzadkich tablicach, a nie tablicach stałych. Można go znaleźć tutaj .

W związku z tym, odpoczywam w moim przypadku, że przyszłość wydajności dla tego konkretnego przypadku użycia nie leży w tablicy.prototyp.przyj, ale raczej w szyku.prototyp.konkat.

Objaśnienia

Zapasowe Tablice

Gdy pewnych członków tablicy po prostu brakuje. Na przykład:

// This is just as an example. In actual code, 
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] =  10;
mySparseArray[17] = "bar";
console.log("Length:   ", mySparseArray.length);
console.log("0 in it:  ", 0 in mySparseArray);
console.log("arr[0]:   ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10]   ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]:  ", mySparseArray[20]);

Alternatywnie, javascript pozwala łatwo inicjalizować zapasowe tablice.

var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];

Array-Likes

Tablica-jak jest obiekt, który posiada co najmniej właściwość length, ale nie został zainicjowany new Array lub []; na przykład poniższe obiekty są klasyfikowane jako podobne do tablicy.

{0: "foo", 1: "bar", length:2}
document.body.children
new Uint8Array(3)
  • jest to tablica podobna do tablicy, ponieważ chociaż jest to tablica (N) (wpisana), wymuszenie jej na tablicy zmienia konstruktor.
(function(){return arguments})()

Obserwuj, co się dzieje, używając metody, która przymusza Polubienia tablic do tablic takich jak slice.

var slice = Array.prototype.slice;
console.log(slice.call({0: "foo", 1: "bar", length:2}));
console.log(slice.call(document.body.children));
console.log(slice.call(new Uint8Array(3)));
console.log(slice.call( function(){return arguments}() ));
  • Uwaga: złą praktyką jest argument funkcji slice ze względu na wydajność.

Obserwuj, co się dzieje, używając metody, któraNie przymusza Polubienia tablicy do tablic takich jak concat.

var empty = [];
console.log(empty.concat({0: "foo", 1: "bar", length:2}));
console.log(empty.concat(document.body.children));
console.log(empty.concat(new Uint8Array(3)));
console.log(empty.concat( function(){return arguments}() ));
 2
Author: Jack Giffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-15 16:21:24

Mamy dwie tablice a i b. kod, który tutaj zrobił, to tablica a wartość jest wypychana do tablicy b.

let a = [2, 4, 6, 8, 9, 15]

function transform(a) {
    let b = ['4', '16', '64']
    a.forEach(function(e) {
        b.push(e.toString());
    });
    return b;
}

transform(a)

[ '4', '16', '64', '2', '4', '6', '8', '9', '15' ]
 0
Author: KARTHIKEYAN.A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 07:02:06

Zamiast funkcji push () użyj funkcji concat dla IE. przykład,

var a=a.concat(a,new Array('amin'));
 -2
Author: user1911703,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-27 01:06:46

To jest działający kod i działa dobrze:

var els = document.getElementsByTagName('input'), i;
var invnum = new Array();
var k = els.length;
for(i = 0; i < k; i++){invnum.push(new Array(els[i].id,els[i].value))}
 -3
Author: user4354031,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-12 12:31:15

Najprościej:

var newArray = dataArray1.slice(0);
 -4
Author: PhuLuong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 09:36:03