Каков более эффективный способ вставить массив в другой массив?
a1 = [1,2,3,4,5];
a2 = [21,22];
newArray - a1.insertAt(2,a2) -> [1,2, 21,22, 3,4,5];
Итерация a2 с использованием splice выглядит немного ужасно с точки зрения производительности, если массив a2 большой.
Спасибо.
Ответы:
Вы можете использовать в
splice
сочетании с некоторымиapply
хитростями:a1 = [1,2,3,4,5]; a2 = [21,22]; a1.splice.apply(a1, [2, 0].concat(a2)); console.log(a1); // [1, 2, 21, 22, 3, 4, 5];
В ES2015 + вместо этого вы можете использовать оператор распространения, чтобы сделать это немного лучше.
a1.splice(2, 0, ...a2);
источник
apply
вызовет исключение stackoverflow. jsfiddle.net/DcHCY Также происходит в jsPerf Я считаю, что в FF и IE порог составляет около 500 тыс.target.slice(0, insertIndex).concat(insertArr, target.slice(insertIndex));
jsperf.com/inserting-an-array-within-an-arrayТеперь вы можете сделать это, если используете ES2015 или новее:
var a1 = [1,2,3,4,5]; var a2 = [21,22]; a1.splice(2, 0, ...a2); console.log(a1) // => [1,2,21,22,3,4,5]
Обратитесь к этому для получения документации по оператору распространения (...) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
источник
Сначала ошибся. Надо было использовать
concat()
вместо этого.var a1 = [1,2,3,4,5], a2 = [21,22], startIndex = 0, insertionIndex = 2, result; result = a1.slice(startIndex, insertionIndex).concat(a2).concat(a1.slice(insertionIndex));
Пример: http://jsfiddle.net/f3cae/1/
Это выражение использует
slice(0, 2)
[docs] для возврата первых двух элементовa1
(где0
- начальный индекс, а2
- элемент deleteCount, ноa1
не изменяется).Промежуточный результат :
[1,2]
Затем он использует
concat(a2)
[docs] для добавленияa2
в конец файла[1,2]
.Промежуточный результат :
[1,2,21,22]
.Затем
a1.slice(2)
вызывается в конце.concat()
в конце этого выражения, что составляет[1,2,21,22].concat(a1.slice(2))
.Вызов
slice(2)
, имеющий положительный целочисленный аргумент, вернет все элементы после второго элемента, считая по натуральным числам (например, есть пять элементов, поэтому[3,4,5]
будут возвращеныa1
). Другой способ сказать это: аргумент индекса единственного числа указывает,a1.slice()
с какой позиции в массиве начинать возвращать элементы (индекс 2 - это третий элемент).Промежуточный результат :
[1,2,21,22].concat([3,4,5])
Наконец, второй
.concat()
прибавляется[3,4,5]
к концу[1,2,21,22]
.Результат :
[1,2,21,22,3,4,5]
Может возникнуть соблазн изменить
Array.prototype
, но можно просто расширить объект Array, используя прототипное наследование, и внедрить указанный новый объект в свои проекты.Однако для тех, кто живет на грани ...
Пример: http://jsfiddle.net/f3cae/2/
Array.prototype.injectArray = function( idx, arr ) { return this.slice( 0, idx ).concat( arr ).concat( this.slice( idx ) ); }; var a1 = [1,2,3,4,5]; var a2 = [21,22]; var result = a1.injectArray( 2, a2 );
источник
Оператор распространения позволяет расширять выражение в местах, где ожидается несколько аргументов (для вызовов функций) или нескольких элементов (для литералов массива).
a2 = [21,22]; a1 = [1,2,...a2,3,4,5];//...a2 is use of spread operator console.log(a1);
источник
На этот вопрос есть несколько действительно творческих ответов. Вот простое решение для тех, кто только начинает работать с массивами. При желании его можно заставить работать вплоть до браузеров, совместимых с ECMAScript 3.
Прежде чем начать, узнайте кое-что о сварке.
Сеть разработчиков Mozilla: Array.prototype.splice ()
Во-первых, разберитесь в двух важных формах
.splice()
.let a1 = [1,2,3,4], a2 = [1,2];
Метод 1) Удалить элементы x (deleteCount), начиная с желаемого индекса.
let startIndex = 0, deleteCount = 2; a1.splice(startIndex, deleteCount); // returns [1,2], a1 would be [3,4]
Метод 2) Удалите элементы после желаемого начального индекса до конца массива.
a1.splice(2); // returns [3,4], a1 would be [1,2]
При использовании
.splice()
, целью может быть разделениеa1
на массивы головы и хвоста с помощью одной из двух форм выше.Используя метод №1, возвращаемое значение станет головой и
a1
хвостом.let head = a1.splice(startIndex, deleteCount); // returns [1,2], a1 would be [3,4]
Теперь одним махом объедините голову, тело (
a2
) и хвостТаким образом, это решение больше похоже на реальный мир, чем любое другое из представленных до сих пор. Разве это не то, что вы сделали бы с Лего? ;-) Вот функция, выполненная методом №2.
/** *@param target Array The array to be split up into a head and tail. *@param body Array The array to be inserted between the head and tail. *@param startIndex Integer Where to split the target array. */ function insertArray(target, body, startIndex) { let tail = target.splice(startIndex); // target is now [1,2] and the head return [].concat(target, body, tail); } let newArray = insertArray([1, 2, 3, 4], ["a", "b"], 2); // [1, 2, "a", "b", 3, 4]
Короче:
/** *@param target Array The array to be split up into a head and tail. *@param body Array The array to be inserted between the head and tail. *@param startIndex Integer Where to split the target array. */ function insertArray(target, body, startIndex) { return [].concat(target, body, target.splice(startIndex)); }
Безопаснее:
/** *@param target Array The array to be split up into a head and tail. *@param body Array The array to be inserted between the head and tail. *@param startIndex Integer Where to split the target array. *@throws Error The value for startIndex must fall between the first and last index, exclusive. */ function insertArray(target, body, startIndex) { const ARRAY_START = 0, ARRAY_END = target.length - 1, ARRAY_NEG_END = -1, START_INDEX_MAGNITUDE = Math.abs(startIndex); if (startIndex === ARRAY_START) { throw new Error("The value for startIndex cannot be zero (0)."); } if (startIndex === ARRAY_END || startIndex === ARRAY_NEG_END) { throw new Error("The startIndex cannot be equal to the last index in target, or -1."); } if (START_INDEX_MAGNITUDE >= ARRAY_END) { throw new Error("The absolute value of startIndex must be less than the last index."); } return [].concat(target, body, target.splice(startIndex)); }
К преимуществам этого решения можно отнести:
1) В решении преобладает простая посылка - заполнить пустой массив.
2) Номенклатура головы, тела и хвоста кажется естественной.
3) Нет двойного звонка
.slice()
. Никаких нарезок.4) Нет
.apply()
. Совершенно ненужно.5) Исключение цепочки методов.
6) Работает в ECMAScript 3 и 5, просто используя
var
вместоlet
илиconst
.** 7) Гарантирует, что голову и хвост можно будет хлопнуть по телу, в отличие от многих других представленных решений. Если вы добавляете массив до или после границ, вы должны хотя бы использовать
.concat()
!!!!Примечание. Использование оператора разбрасывания
...
значительно упрощает выполнение всего этого.источник
Я хотел найти способ сделать это
splice()
без итераций: http://jsfiddle.net/jfriend00/W9n27/ .a1 = [1,2,3,4,5]; a2 = [21,22]; a2.unshift(2, 0); // put first two params to splice onto front of array a1.splice.apply(a1, a2); // pass array as arguments parameter to splice console.log(a1); // [1, 2, 21, 22, 3, 4, 5];
В форме функции общего назначения:
function arrayInsertAt(destArray, pos, arrayToInsert) { var args = []; args.push(pos); // where to insert args.push(0); // nothing to remove args = args.concat(arrayToInsert); // add on array to insert destArray.splice.apply(destArray, args); // splice it in }
источник
a2
массив, что, вероятно, весьма нежелательно. Кроме того, вам не нужно переходить к,Array.prototype
когда у вас есть функция среза прямо тамa1
илиa2
.apply()
метод.Array.prototype.splice
vsa1.splice
:).concat
возвращает новый массив, он не изменяет существующий, какsplice
. Должно бытьargs = args.concat(arrayToInsert);
var a1 = [1,2,3,4,5]; var a2 = [21,22]; function injectAt(d, a1, a2) { for(var i=a1.length-1; i>=d; i--) { a1[i + a2.length] = a1[i]; } for(var i=0; i<a2.length; i++) { a1[i+d] = a2[i]; } } injectAt(2, a1, a2); alert(a1);
источник
Вот моя версия без особых ухищрений:
function insert_array(original_array, new_values, insert_index) { for (var i=0; i<new_values.length; i++) { original_array.splice((insert_index + i), 0, new_values[i]); } return original_array; }
источник
.apply()
.Если вы хотите вставить другой массив в массив, не создавая новый, самый простой способ - использовать либо,
push
либоunshift
сapply
Например:
a1 = [1,2,3,4,5]; a2 = [21,22]; // Insert a1 at beginning of a2 a2.unshift.apply(a2,a1); // Insert a1 at end of a2 a2.push.apply(a2,a1);
Это работает , потому как
push
иunshift
принимать переменное число аргументов. Бонус, вы можете легко выбрать, с какого конца прикрепить массив!источник
a1.concat(a2)
илиa2.concat(a1)
я придумал что-то более легкое, чем то, что вы предлагаете. Однако проблема заключается во вставке массива между границами массива, а не только в добавлении массива в начало или конец. ;-)Как упоминалось в другом потоке, приведенные выше ответы не будут работать в очень больших массивах (200K элементов). См. Альтернативный ответ здесь, включающий соединение и ручное нажатие: https://stackoverflow.com/a/41465578/1038326
Array.prototype.spliceArray = function(index, insertedArray) { var postArray = this.splice(index); inPlacePush(this, insertedArray); inPlacePush(this, postArray); function inPlacePush(targetArray, pushedArray) { // Not using forEach for browser compatability var pushedArrayLength = pushedArray.length; for (var index = 0; index < pushedArrayLength; index++) { targetArray.push(pushedArray[index]); } } }
источник