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

IT技术 javascript arrays prepend
2021-02-25 11:19:16

假设我有一个大小为N(where 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;
}
6个回答

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

[编辑]

这个jsPerf 基准测试表明,如果你可以就地修改数组,那么unshift至少在几个浏览器中要快得多,不管可能不同的 big-O 性能如果您真的无法改变原始数组,那么您将执行以下代码段之类的操作,这似乎并不比您的解决方案快得多:

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

[编辑 2]

为了完整起见,可以使用以下函数代替 OP 的示例prependArray(...)来利用 Arrayunshift(...)方法:

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

var x = [1, 2, 3];
var y = prepend(0, x);
// x => [1, 2, 3];
// y => [0, 1, 2, 3];
console.log({ x, y });

此解决方案只有一个问题。unshift() 不返回它的length,而不是这个答案中的数组吗? w3schools.com/jsref/jsref_unshift.asp
2021-04-23 11:19:16
unshift 是 shift 的补充函数。称其为“前置”将是一个奇怪的选择。Unshift 是移动,就像 push 是弹出一样。
2021-04-29 11:19:16
push并且unshift都包含u,而popshift没有。
2021-04-30 11:19:16
@ScottStaffordunshift听起来更适合这样的数组操作(它或多或少地在物理上移动元素)。prepend会更适合于链表,在那里你字面上前面加上元素。
2021-05-02 11:19:16
谁决定叫prependunshift”?
2021-05-16 11:19:16

在 ES6 中,您现在可以使用展开运算符创建一个新数组,并将新元素插入到原始元素之前。

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

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

2018-08-17 更新:性能

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

你没有提到与相比所花费的时间 unshift
2021-05-05 11:19:16
@FrankTan :干杯 :) +1
2021-05-12 11:19:16
这应该在 2017 年投票通过。它很简洁。通过使用传播,它返回新的流,这对于链接进一步的修改很有用。它也是纯的(意味着 a 和 b 不受影响)
2021-05-13 11:19:16
谢谢@ShashankVivek。我打算在这个答案中提出一种我认为更令人难忘和简洁的替代语法。我会更新的。
2021-05-17 11:19:16

如果您将一个数组添加到另一个数组的前面,则仅使用concat. 所以:

const newArray = [1, 2, 3].concat([4, 5]);
newArray; // [1, 2, 3, 4, 5]

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

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

它对 oneliner 有好处,因为 concat 返回数组,而 unshift 返回新长度
2021-04-27 11:19:16
哦,是的,我忘记了unshift但请注意,a) 会改变 oldArray 而concat不会(因此哪个更适合您取决于具体情况),并且 b) 它只插入一个元素。
2021-05-04 11:19:16
哇,这要慢得多。好吧,正如我所说,它正在制作数组的副本(并创建一个新数组[0]),而 unshift 正在原地改变它。但两者都应该是 O(N)。也为该网站的链接欢呼——看起来非常方便。
2021-05-11 11:19:16

如果您想添加数组(a1 与数组 a2),您可以使用以下命令:

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

如果您需要保留旧数组,请将旧数组切片并将新值移至切片的开头。

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