假设我有一个大小为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;
}
答案 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创建一个新数组,并在原始元素之前插入新元素。
// Prepend a single item.
const a = [1, 2, 3];
console.log([0, ...a]);
&#13;
// Prepend an array.
const a = [2, 3];
const b = [0, 1];
console.log([...b, ...a]);
&#13;
我打算在这个答案中提出一种我认为更难忘和简洁的替代语法。应该注意的是,根据一些基准测试(参见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倍。
答案 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]