将值添加到数组的最有效方法

时间:2011-06-01 02:47:29

标签: javascript arrays prepend

假设我有一个大小为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;
}

10 个答案:

答案 0 :(得分:437)

我不确定在big-O方面效率更高,但肯定使用unshift方法更简洁:

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

<强> [编辑]

这个jsPerf benchmark表明unshift在至少几个浏览器中速度要快得多,无论可能有什么不同的大O性能如果你可以修改数组到位。如果你真的不能改变原始数组那么你会做类似下面的代码片段,它似乎没有比你的解决方案快得多:

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

[编辑2]

为了完整性,可以使用以下函数代替OP的示例prependArray(...)来利用数组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];

答案 1 :(得分:45)

如果要将数组添加到另一个数组的前面,则使用concat会更有效。所以:

var newArray = values.concat(oldArray);

但是这仍然是oldArray大小的O(N)。不过,它比手动迭代oldArray更有效。此外,根据细节,它可能会对您有所帮助,因为如果您要预先添加许多值,最好先将它们放入数组中,然后最后将oldArray连接起来,而不是单独添加每个值。

没有办法比oldArray的O(N)更好,因为数组存储在连续的内存中,第一个元素处于固定位置。如果要在第一个元素之前插入,则需要移动所有其他元素。如果您需要解决此问题,请执行@GWW所说的内容并使用链接列表或不同的数据结构。

答案 2 :(得分:45)

使用ES6,您现在可以使用spread operator创建一个新数组,并在原始元素之前插入新元素。

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

&#13;
&#13;
// Prepend an array.
const a = [2, 3];
const b = [0, 1];
console.log([...b, ...a]);
&#13;
&#13;
&#13;

更新2018-08-17:性能

我打算在这个答案中提出一种我认为更难忘和简洁的替代语法。应该注意的是,根据一些基准测试(参见this other answer),这种语法明显变慢。除非您在循环中执行许多这些操作,否则这可能无关紧要。

答案 3 :(得分:32)

如果您想预先添加数组(a1和数组a2),您可以使用以下内容:

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

答案 4 :(得分:6)

如果您需要保留旧数组, 切换旧的并取消新值(s) 到切片的开头。

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
*/

答案 5 :(得分:3)

有特殊方法:

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]

答案 6 :(得分:2)

我对不同的前置方法进行了一些新的测试。 对于小阵列(&lt; 1000 elems),领导者用于循环耦合推送方法。 对于大型阵列,Unshift方法成为领导者。

但这种情况仅适用于Chrome浏览器。在Firefox中,unshift具有非常棒的优化功能,并且在所有情况下都更快。

在所有浏览器中,ES6传播速度要慢100倍。

https://jsbench.me/cgjfc79bgx/1

答案 7 :(得分:0)

就地前置示例:

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

A.unshift(...B)

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

答案 8 :(得分:0)

调用unshift仅返回新数组的长度。 因此,要在开头添加一个元素并返回一个新数组,我这样做:

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

或仅使用传播算子:

[ newVal, ...array ]

这样,原始阵列将保持不变。

答案 9 :(得分:0)

const x = 1
const list = [2, 3, 4]
const newList = [x].concat(list) // [1, 2, 3, 4]