Наиболее эффективный способ добавления значения к массиву

Предполагая, что у меня есть массив размером N (где N > 0), существует ли более эффективный способ добавления массива, который не требует шагов O (N + 1)?

В коде, по существу, то, что я делаю сейчас,

function prependArray(value, oldArray) {
  var newArray = new Array(value);

  for(var i = 0; i < oldArray.length; ++i) {
    newArray.push(oldArray[i]);
  }

  return newArray;
}

Ответ 1

Я не уверен насчет более эффективного с точки зрения big-O, но, конечно, использование метода unshift более лаконично:

var a = [1, 2, 3, 4];
a.unshift(0);
a; // => [0, 1, 2, 3, 4]

[Редактировать]

Этот тест jsPerf показывает, что unshift работает прилично быстрее, по крайней мере, в нескольких браузерах, независимо от возможной разной производительности big-O, если вы согласны с изменением массива на месте. Если вы действительно не можете изменить исходный массив, сделайте что-то вроде приведенного ниже фрагмента, который, похоже, не будет значительно быстрее, чем ваше решение:

a.slice().unshift(0); // Use "slice" to avoid mutating "a".

[Редактировать 2]

Для полноты можно использовать следующую функцию вместо примера OP prependArray(...) чтобы воспользоваться преимуществом метода Array unshift(...):

function prepend(value, array) {
  var newArray = array.slice();
  newArray.unshift(value);
  return newArray;
}

var x = [1, 2, 3];
var y = prepend(0, x);
y; // => [0, 1, 2, 3];
x; // => [1, 2, 3];

Ответ 2

Если вы добавляете массив к фронту другого массива, более эффективно использовать concat. Итак:

var newArray = values.concat(oldArray);

Но это все равно будет O (N) в размере oldArray. Тем не менее, он более эффективен, чем ручное повторение по сравнению с oldArray. Кроме того, в зависимости от деталей, это может вам помочь, потому что, если вы собираетесь добавить много значений, лучше сначала поместить их в массив, а затем конкатенерировать oldArray на конце, а не добавлять каждый отдельно.

Нет никакого способа сделать лучше, чем O (N) в размере oldArray, потому что массивы хранятся в непрерывной памяти с первым элементом в фиксированной позиции. Если вы хотите вставить перед первым элементом, вам нужно переместить все остальные элементы. Если вам нужно обойти это, сделайте то, что сказал @GWW, и используйте связанный список или другую структуру данных.

Ответ 3

С ES6 вы можете теперь использовать оператор распространения, чтобы создать новый массив с вашими новыми элементами, вставленными перед исходными элементами.

// Prepend a single item.
const a = [1, 2, 3];
console.log([0, ...a]);

Ответ 4

Если вы хотите добавить массив (a1 с массивом a2), вы можете использовать следующее:

var a1 = [1, 2];
var a2 = [3, 4];
Array.prototype.unshift.apply(a1, a2);
console.log(a1);
// => [3, 4, 1, 2]

Ответ 5

f вам нужно сохранить старый массив, отрежьте старый и не сдвиньте новое значение (ы) к началу среза.

var oldA=[4,5,6];
newA=oldA.slice(0);
newA.unshift(1,2,3)

oldA+'\n'+newA

/*  returned value:
4,5,6
1,2,3,4,5,6
*/

Ответ 6

Существует специальный метод:

a.unshift(value);

Но если вы хотите добавить несколько элементов в массив, было бы быстрее использовать такой метод:

var a = [1, 2, 3],
    b = [4, 5];

function prependArray(a, b) {
    var args = b;
    args.unshift(0);
    args.unshift(0);
    Array.prototype.splice.apply(a, args);
}

prependArray(a, b);
console.log(a); // -> [4, 5, 1, 2, 3]

Ответ 7

У меня есть несколько свежих тестов различных методов приготовления. Для небольших массивов (<1000 элементов) лидером является цикл, связанный с методом push. Для огромных массивов метод Unshift становится лидером.

Но эта ситуация актуальна только для браузера Chrome. В Firefox unshift имеет потрясающую оптимизацию и работает быстрее во всех случаях.

ES6 распространяется в 100+ раз медленнее во всех браузерах.

https://jsbench.me/cgjfc79bgx/1

Ответ 8

Пример добавления на месте:

var A = [7,8,9]
var B = [1,2,3]

A.unshift(...B)

console.log(A) // [1,2,3,7,8,9]

Ответ 9

Вызов unshift возвращает только длину нового массива. Итак, чтобы добавить элемент в начале и вернуть новый массив, я сделал это:

let newVal = 'someValue';
let array = ['hello', 'world'];
[ newVal ].concat(array);

или просто с оператором распространения:

[ newVal, ...array ]

Таким образом, исходный массив остается нетронутым.