在JavaScript中创建任意长度的零填充数组最有效的方法是什么?


当前回答

循环代码最短

a=i=[];for(;i<100;)a[i++]=0;

edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;

安全var版本

var a=[],i=0;for(;i<100;)a[i++]=0;

edit:
for(var i=100,a=[];i--;)a[i]=0;

其他回答

如果使用ES6,则可以像这样使用Array.from():

Array.from({ length: 3 }, () => 0);
//[0, 0, 0]

结果与相同

Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]

因为

Array.from({ length: 3 })
//[undefined, undefined, undefined]

用预先计算的值填充数组的优雅方式

这里有另一种使用ES6的方法,到目前为止没有人提到:

> Array.from(Array(3), () => 0)
< [0, 0, 0]

它通过传递一个map函数作为Array.from的第二个参数来工作。

在上面的示例中,第一个参数分配一个由3个位置组成的数组,其中填充了未定义的值,然后lambda函数将每个位置映射到值0。

虽然Array(len).fill(0)更短,但如果您需要先进行一些计算来填充数组,它就不起作用了(我知道这个问题并没有提出,但很多人最终都在这里寻找这个问题)。

例如,如果需要包含10个随机数的数组:

> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]

它比同类产品更简洁(更优雅):

const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
    numbers[i] = Math.round(10 * Math.random());
}

此方法还可用于通过利用回调中提供的索引参数生成数字序列:

> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

额外答案:使用String repeat()填充数组

由于这个答案受到了很多关注,我也想展示一下这个很酷的技巧。虽然不如我的主要答案有用,但将介绍一个仍然不是很有名,但非常有用的Stringrepeat()方法。诀窍如下:

> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]

酷吧?repeat()是创建字符串的一种非常有用的方法,该字符串将原始字符串重复一定次数。之后,split()为我们创建一个数组,然后将其映射()到所需的值。按步骤分解:

> "?".repeat(10)
< "??????????"

> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]

> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]

截至ECMAScript2016,大型阵列有一个明确的选择。

由于这一答案在谷歌搜索中仍然排名靠前,所以这里有一个2017年的答案。

这里有一个当前的jsbench,其中有几十种流行的方法,包括迄今为止提出的许多方法。如果你找到更好的方法,请添加、分叉和分享。

我想指出,没有真正最有效的方法来创建任意长度的零填充数组。您可以优化速度,也可以优化清晰度和可维护性——根据项目的需要,两者都可以被视为更有效的选择。

在优化速度时,您需要:使用文字语法创建数组;设置长度,初始化迭代变量,并使用while循环遍历数组。这里有一个例子。

常量arr=[];arr.length=120000;设i=0;而(i<120000){arr[i]=0;i++;}

另一种可能的实施方式是:

(arr = []).length = n;
let i = 0;
while (i < n) {
    arr[i] = 0;
    i++;
}

但我强烈反对在实践中使用第二次植入,因为它不太清楚,也不允许在数组变量上保持块范围。

这比用for循环填充要快得多,比标准方法快90%左右

const arr = Array(n).fill(0);

但这种填充方法由于其清晰、简洁和可维护性,对于较小的阵列来说仍然是最有效的选择。除非您制作了大量长度为数千或更多的阵列,否则性能差异可能不会让您丧命。

其他一些重要的注意事项。大多数风格指南都建议您在使用ES6或更高版本时,如果没有非常特殊的原因,不要再使用var。对于不会被重新定义的变量使用const,对于会被重新定义变量使用let。MDN和Airbnb的风格指南是获取更多最佳实践信息的好地方。这些问题并不涉及语法,但重要的是,在搜索大量新旧答案时,熟悉JS的人必须了解这些新标准。

我没有反对:

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);

Zertosh建议,但在一个新的ES6阵列扩展中,您可以使用fill方法在本地执行此操作。现在IE edge、Chrome和FF都支持它,但请查看兼容性表

new Array(3).fill(0)将为您提供[0,0,0]。您可以用任何值填充数组,如new array(5).fill('abc')(甚至对象和其他数组)。

除此之外,您还可以使用填充修改以前的阵列:

arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5)  # what to fill, start, end

这给了你:[1,2,3,9,9,6]

虽然这是一个旧线程,但我想添加我的2美分。不知道这有多慢/快,但它是一个快速的单线。以下是我所做的:

如果我想预先填写数字:

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]

如果我想预先填充字符串:

Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]

其他答案表明:

new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]

但如果您想要0(数字)而不是“0”(字符串中为零),则可以执行以下操作:

new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]