Копировать элементы массива в другой массив

У меня есть массив dataArray JavaScript, который я хочу вставить в новый массив newArray. За исключением того, что я не хочу, чтобы newArray[0] был dataArray. Я хочу вставить все элементы в новый массив:

var newArray = [];

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

или даже лучше:

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

Теперь новый массив содержит все значения отдельных массивов данных. pushValues ли какие-то сокращения, такие как pushValues поэтому мне не нужно перебирать каждый отдельный dataArray, добавляя элементы по одному?

Ответ 1

Используйте функцию concat, например:

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

Значение newArray будет [1, 2, 3, 4] (arrayA и arrayB не измениться; concat создает и возвращает новый массив для результата).

Ответ 2

Если ваши массивы не огромны (см. ниже), вы можете использовать метод push() для массива, к которому вы хотите добавить значения. push() может принимать несколько параметров, поэтому вы можете использовать его метод apply(), чтобы передать массив значений, которые нужно нажать в качестве списка параметров функции. Это имеет преимущество перед использованием concat() добавления элементов в массив вместо того, чтобы создавать новый массив.

Однако, похоже, что для больших массивов (порядка 100 000 членов или более) этот трюк может выйти из строя. Для таких массивов использование цикла является лучшим подходом. Подробнее см. fooobar.com/questions/13475/....

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

Возможно, вы захотите обобщить это на функцию:

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

... или добавить его в прототип Array:

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

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

... или эмулировать исходный метод push(), разрешив несколько параметров, используя тот факт, что concat(), например push(), позволяет несколько параметров:

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

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

Здесь приведенная на основе цикла версия последнего примера, подходящая для больших массивов и всех основных браузеров, включая IE <= 8:

Array.prototype.pushArray = function() {
    var toPush = this.concat.apply([], arguments);
    for (var i = 0, len = toPush.length; i < len; ++i) {
        this.push(toPush[i]);
    }
};

Ответ 3

Я добавлю еще один ответ на будущее

В ECMAScript 6 вы можете использовать синтаксис Spread:

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

console.log(arr1)

Ответ 4

Нашел элегантный способ из 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']

Или вы можете использовать функцию spread operator для ES6:

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

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]

Ответ 5

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)

Решает ли ваша проблема?

Ответ 6

Для меня кажется мне самым простым:

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

Поскольку "push" принимает переменное количество аргументов, вы можете использовать метод apply push функции для нажатия всех элементов другого массива. Он строит вызов push с использованием его первого аргумента (здесь "newArray") как "this", а элементы массива - в качестве остальных аргументов.

slice в первом выражении получает копию первого массива, поэтому вы не изменяете его.

Обновление Если вы используете версию javascript с доступным срезом, вы можете упростить выражение push:

newArray.push(...dataArray2)

Ответ 7

Есть несколько ответов, касающихся Array.prototype.push.apply. Вот яркий пример:

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]

Ответ 8

Функция ниже не имеет проблемы с длиной массивов и работает лучше, чем все предлагаемые решения:

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

К сожалению, jspref отказывается принимать мои заявки, поэтому здесь они являются результатами с помощью 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

где

для цикла и нажатия:

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

Нажмите Применить:

target.push.apply(target, source);
Оператор распространения

:

    target.push(...source);

и, наконец, "заданная длина и цикл" - это указанная выше функция

Ответ 9

В JavaScript ES6 вы можете использовать оператор... в качестве оператора распространения, который по существу преобразует массив в значения. Затем вы можете сделать что-то вроде этого:

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

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

Хотя синтаксис является кратким, я не знаю, как это работает внутри и как это влияет на производительность больших массивов.

Ответ 10

Здесь путь ES6

var newArray = [];
let dataArray1 = [1,2,3,4]
let dataArray2 = [5,6,7,8]
newArray = [...dataArray1, ...dataArray2]
console.log(newArray)

Ответ 11

A 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀

Для факта, выполняется тест производительности в jsperf и проверка некоторых вещей в консоли. Для исследования используется веб-сайт irt.org. Ниже собрана коллекция всех этих источников вместе с примером функции внизу.

╔═══════════════╦══════╦═════════════════╦═══════════════╦═════════╦══════════╗
║ 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=inputOne[0]; i !== oneLen; ++i) {
        tmp = inputOne[i];
        if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
    }
    for (var two=0; i !== newLen; ++i, ++two) {
        tmp = inputTwo[two];
        if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
    }
    return newArr;
}

Как видно из вышеизложенного, я бы сказал, что Concat - это почти всегда способ достижения как производительности, так и способности сохранять редкость запасных массивов. Затем для лайков массива (таких как DOMNodeLists, как document.body.children) я бы рекомендовал использовать цикл for, поскольку он является вторым по производительности и единственным другим методом, который сохраняет разреженные массивы. Ниже мы быстро рассмотрим, что имеется в виду под разреженными массивами и подобными массивами, чтобы устранить путаницу.

A 𝗙𝘂𝘁𝘂𝗿𝗲

Поначалу некоторые люди могут подумать, что это случайность, и что производители браузеров в конечном итоге доберутся до оптимизации Array.prototype.push, чтобы быть достаточно быстрыми, чтобы превзойти Array.prototype.concat. НЕПРАВИЛЬНО! Array.prototype.concat всегда будет быстрее (в принципе, по крайней мере), потому что это просто копирование и вставка данных. Ниже приведена упрощенная наглядная диаграмма того, как может выглядеть реализация 32-битного массива (обратите внимание, что реальные реализации намного сложнее)

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

Как видно выше, все, что вам нужно сделать, чтобы скопировать что-то подобное, почти так же просто, как копировать его байт за байтом. С Array.prototype.push.apply это намного больше, чем просто копирование и вставка данных. ".Apply" должен проверить каждый индекс в массиве и преобразовать его в набор аргументов, прежде чем передать его в Array.prototype.push. Затем Array.prototype.push должен дополнительно выделять больше памяти каждый раз, и (для некоторых реализаций браузера) может даже пересчитывать некоторые данные поиска позиции для разреженности.

Альтернативный способ думать об этом - это. Исходный массив один - это большая стопка бумаг, сшитых вместе. Массив источника два - это еще одна большая стопка бумаг. Будет ли для вас быстрее

  1. Пойдите в магазин, купите достаточно бумаги, необходимой для копии каждого исходного массива. Затем вставьте каждый стопку бумаги в исходный массив через копировальный аппарат и скрепите получающиеся две копии вместе.
  2. Пойдите в магазин, купите достаточно бумаги для одной копии первого исходного массива. Затем вручную скопируйте исходный массив на новую бумагу, чтобы заполнить все пустые редкие пятна. Затем вернитесь в магазин и купите достаточно бумаги для второго источника. Затем просмотрите второй исходный массив и скопируйте его, не оставляя пробелов в копии. Затем скрепите все скопированные документы вместе.

В приведенной выше аналогии вариант № 1 представляет Array.prototype.concat, а № 2 представляет Array.prototype.push.apply. Давайте проверим это с помощью аналогичного JSperf, отличающегося только тем, что этот тестирует методы с разреженными массивами, а не с массивными массивами. Его можно найти прямо здесь.

Поэтому я остановлюсь на том, что будущее производительности для этого конкретного варианта использования не в Array.prototype.push, а в Array.prototype.concat.

𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀

A 𝗔𝗿𝗿𝗮𝘆𝘀

Когда некоторые члены массива просто отсутствуют. Например:

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

Ответ 12

У нас есть два массива a и b. код, который здесь представляет собой массив, вводится в массив 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' ]

Ответ 13

Если вы хотите изменить исходный массив, вы можете распространить и нажать:

var source = [1, 2, 3];
var range = [5, 6, 7];
var length = source.push(...range);

console.log(source); // [ 1, 2, 3, 5, 6, 7 ]
console.log(length); // 6

Если вы хотите, чтобы в массив source входили только элементы одного типа (например, не смешивая числа и строки), используйте TypeScript.

/**
 * Adds the items of the specified range array to the end of the source array.
 * Use this function to make sure only items of the same type go in the source array.
 */
function addRange<T>(source: T[], range: T[]) {
    source.push(...range);
}

Ответ 14

вместо функции push() используется функция concat для IE. Например,

var a=a.concat(a,new Array('amin'));

Ответ 15

Это рабочий код, и он отлично работает:

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

Ответ 16

Самый простой:

var newArray = dataArray1.slice(0);