Кажется, не существует способа расширить существующий массив JavaScript другим массивом, то есть эмулировать extend
метод Python .
Я хочу добиться следующего:
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
Я знаю, что есть a.concat(b)
метод, но он создает новый массив вместо простого расширения первого. Я хотел бы алгоритм, который работает эффективно, когда a
значительно больше, чем b
(то есть тот, который не копирует a
).
Примечание: это не дубликат Как добавить что-либо в массив? - цель здесь состоит в том, чтобы добавить все содержимое одного массива в другой и сделать это «на месте», т.е. без копирования всех элементов расширенного массива.
a.push(...b)
. По концепции он похож на лучший ответ, но обновлен для ES6.Ответы:
.push
Метод может принимать несколько аргументов. Вы можете использовать оператор распространения, чтобы передать все элементы второго массива в качестве аргументов.push
:Если ваш браузер не поддерживает ECMAScript 6, вы можете использовать
.apply
вместо этого:Или, может быть, если вы думаете, что это яснее:
Обратите внимание, что все эти решения завершатся с ошибкой переполнения стека, если массив
b
слишком длинный (проблема начинается с 100 000 элементов, в зависимости от браузера).Если вы не можете гарантировать, что
b
он достаточно короткий, вам следует использовать стандартную методику, основанную на циклах, описанную в другом ответе.источник
push
метод массива может принимать любое количество аргументов, которые затем помещаются в конец массива. Поэтомуa.push('x', 'y', 'z')
действительный вызов , который будет распространятьсяa
на 3 -х элементов.apply
является методом любой функции, которая принимает массив и использует его элементы, как если бы они все были заданы явно как позиционные элементы для функции. Такa.push.apply(a, ['x', 'y', 'z'])
же расширил бы массив на 3 элемента. Кроме того,apply
в качестве первого аргумента принимает контекст (мыa
снова передаем его для добавленияa
).[].push.apply(a, b)
.Обновление 2018 : Лучший ответ новее один из моих :
a.push(...b)
. Не одобряйте это больше, так как он никогда не отвечал на вопрос, но это был хак 2015 года вокруг первого попадания в Google :)Для тех, кто просто искал "Расширение массива JavaScript" и получил здесь, вы можете очень хорошо использовать
Array.concat
.Concat вернет копию нового массива, поскольку запускатель потоков не захотел. Но вам может быть все равно (конечно, для большинства видов использования это будет хорошо).
Для этого есть также хороший сахар ECMAScript 6 в виде оператора распространения:
(Это также копирует.)
источник
arr.push(...arr2)
новее и лучше и технически правильно (тм) ответ на этот конкретный вопрос.Вы должны использовать технику на основе цикла. Другие ответы на этой странице, основанные на использовании,
.apply
могут не работать для больших массивов.Довольно краткая реализация, основанная на циклах:
Затем вы можете сделать следующее:
Ответ DzinX (с использованием push.apply) и других
.apply
основанных на нем методов завершается неудачей, когда добавляемый нами массив большой (тесты показывают, что для меня большой размер составляет> 150 000 записей в Chrome и> 500 000 записей в Firefox). Вы можете увидеть эту ошибку, возникающую в этом jsperf .Ошибка возникает из-за превышения размера стека вызовов при вызове Function.prototype.apply с большим массивом в качестве второго аргумента. (У MDN есть примечание об опасностях превышения размера стека вызовов с помощью Function.prototype.apply - см. Раздел «Применение и встроенные функции».)
Для сравнения скорости с другими ответами на этой странице, проверьте этот jsperf (благодаря EaterOfCode). Реализация на основе циклов похожа по скорости на использование
Array.push.apply
, но имеет тенденцию быть немного медленнее, чемArray.slice.apply
.Интересно, что если массив, который вы добавляете, является разреженным,
forEach
основанный метод выше может использовать преимущества разреженности и опережать.apply
основанные методы; Проверьте этот jsperf, если вы хотите проверить это для себя.Между прочим, не поддавайтесь искушению (как я!) Дополнительно сократить реализацию forEach до:
потому что это приводит к результатам мусора! Почему? Потому что
Array.prototype.forEach
предоставляет три аргумента вызываемой функции - это: (element_value, element_index, source_array). Все они будут помещены в ваш первый массив для каждой итерации,forEach
если вы используете «forEach (this.push, this)»!источник
.push.apply
на самом деле намного быстрее, чем.forEach
в v8, самый быстрый - все еще встроенный цикл..forEach
происходит быстрее, чем.push.apply
в Chrome / Chromium (во всех версиях начиная с v25). Я не смог протестировать v8 изолированно, но если у вас есть, пожалуйста, свяжите свои результаты. См. Jsperf: jsperf.com/array-extending-push-vs-concat/5undefined
, так.forEach
что пропустить их, что делает его самым быстрым..splice
на самом деле самый быстрый ?! jsperf.com/array-extending-push-vs-concat/18Я чувствую себя самым элегантным в эти дни:
В статье MDN об операторе спреда в ES2015 (ES6) упоминается этот приятный сладкий путь:
Обратите внимание, что он
arr2
не может быть огромным (не более 100 000 элементов), потому что стек ответов переполняется, согласно ответу jcdude.источник
arr1.push(arr2)
. Это может быть проблемой,arr1 = []; arr2=['a', 'b', 'd']; arr1.push(arr2)
в результате чего получается массив массивов,arr1 == [['a','b','d']]
а не два вместе взятых. Это простая ошибка. По этой причине я предпочитаю ваш второй ответ ниже. stackoverflow.com/a/31521404/4808079.concat
, что второй аргумент не должен быть массивом. Это может быть достигнуто путем объединения оператора распространения сconcat
, напримерarr1.push(...[].concat(arrayOrSingleItem))
Сначала несколько слов о
apply()
JavaScript, чтобы понять, почему мы его используем:Push ожидает список элементов для добавления в массив. Однако
apply()
метод принимает ожидаемые аргументы для вызова функции в виде массива. Это позволяет нам легко помещатьpush
элементы одного массива в другой с помощью встроенногоpush()
метода.Представьте, что у вас есть эти массивы:
и просто сделайте это:
Результатом будет:
То же самое можно сделать в ES6 с помощью оператора распространения ("
...
") следующим образом:Короче и лучше, но не полностью поддерживается на данный момент во всех браузерах.
Также, если вы хотите переместить все из массива
b
вa
пустуюb
в процессе, вы можете сделать это:и результат будет следующим:
источник
while (b.length) { a.push(b.shift()); }
правильно?Если вы хотите использовать jQuery, есть $ .merge ()
Пример:
Результат: a =
[1, 2, 3, 4, 5]
источник
jQuery.merge()
?Мне нравится
a.push.apply(a, b)
метод, описанный выше, и если вы хотите, вы всегда можете создать библиотечную функцию следующим образом:и использовать это так
источник
Это можно сделать с помощью
splice()
:Но несмотря на то, что он уродлив, он не быстрее
push.apply
, по крайней мере, в Firefox 3.0.источник
Это решение работает для меня (используя оператор распространения ECMAScript 6):
источник
Вы можете создать Polyfill для расширения, как у меня ниже. Это добавит в массив; на месте и вернуть себя, так что вы можете связать другие методы.
источник
Объединяя ответы ...
источник
Еще одно решение для объединения более двух массивов
Затем позвоните и распечатайте как:
Выход будет:
Array [1, 2, 3, 4, 5, 6, 7]
источник
Ответ супер прост.
Concat действует очень похоже на конкатенацию строк JavaScript. Он вернет комбинацию параметра, который вы поместили в функцию concat в конце массива, для которого вы вызываете функцию. Суть в том, что вы должны присвоить возвращаемое значение переменной, иначе оно будет потеряно. Так например
источник
Array.prototype.concat()
MDN, это вернет новый массив , он не будет добавлен к существующему массиву, как явно просил OP.Используйте
Array.extend
вместоArray.push
> 150000 записей.источник
Супер просто, не рассчитывать на операторов спреда или применять, если это проблема.
После выполнения некоторых тестов производительности это очень медленно, но отвечает на вопрос о том, чтобы не создавать новый массив. Concat работает значительно быстрее, даже jQuery
$.merge()
делает это.https://jsperf.com/merge-arrays19b/1
источник
.forEach
а не.map
если вы не используете возвращаемое значение. Это лучше передает смысл вашего кода..map
но вы также можете сделатьb.forEach(function(x) { a.push(x)} )
. На самом деле я добавил это в тест jsperf, и это на волосок быстрее, чем map. Все еще супер медленно..map
сюда выглядит очень странно. Это было бы как звонитьb.filter(x => a.push(x))
. Это работает, но это сбивает с толку читателя, подразумевая, что что-то происходит, когда это не так..map()
делает, и это проблема. Это знание заставит меня думать, что вам нужен результирующий массив, иначе было бы неплохо использовать его,.forEach()
чтобы заставить читателя быть осторожным с побочными эффектами функции обратного вызова. Строго говоря, ваше решение создает дополнительный массив натуральных чисел (результатыpush
), а вопрос гласит: «без создания нового массива».