【问题标题】:How to create an array containing 1...N如何创建一个包含 1...N 的数组
【发布时间】:2022-01-09 21:39:31
【问题描述】:

我正在寻找下面的任何替代方法来创建一个包含 1 到 N 的 JavaScript 数组,其中 N 仅在运行时知道。

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

对我来说,感觉应该有一种没有循环的方法。

【问题讨论】:

  • 读完整个页面后,我得出的结论是,您自己的简单 for 循环是最简单、最易读、最不容易出错的。
  • 如果有人需要更高级的东西,我创建了一个 node.js 库,用于处理数字、字母、负/正范围等github.com/jonschlinkert/fill-range。它在github.com/jonschlinkert/braces 中用于大括号扩展,在github.com/jonschlinkert/micromatch 中用于全局模式
  • 另一种方法可以是这样的:Array.from({length : 10}, (_, v) => v)
  • @SahilGupta 差不多。如果我们想要 1 到 10,我们需要加 1,例如这个: Array.from({length : 10}, (_, v) => v+1)
  • 将 foo 定义为 object {} 而不是数组,然后使用 foo[i] = i; 添加您自己的索引;

标签: javascript arrays


【解决方案1】:

在 ES6 中使用数组 from()keys() 方法。

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

使用spread operator的较短版本。

[...Array(10).keys()]
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

从 1 开始,将 map 函数传递给数组 from(),并使用具有 length 属性的对象:

Array.from({length: 10}, (_, i) => i + 1)
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

【讨论】:

  • 请注意,这将始终从 0 开始。需要将 map 链接到数组以将值 ([...Array(10).keys()].map(x =&gt; x++);) 调整为从 1 开始
  • 只需将map(x =&gt; x++) 更改为map(x =&gt; ++x),因为在返回值之后会发生优先级递增:)
  • 呃什么!?为什么map 可以简单地slice[...Array(N+1).keys()].slice(1)
  • 或者不要使用keys,只有一张地图-> Array.from(Array(10)).map((e,i)=&gt;i+1)
  • 或者不使用键和映射,只传递一个映射函数给fromArray.from(Array(10), (e,i)=&gt;i+1)
【解决方案2】:

你可以这样做:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

或随机值:

Array.apply(null, {length: N}).map(Function.call, Math.random)

结果:[0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.55775759153655732, 459153565732, 170.16]

说明

首先,请注意Number.call(undefined, N) 等价于Number(N),它只返回N。我们稍后会用到这个事实。

Array.apply(null, [undefined, undefined, undefined]) 等价于Array(undefined, undefined, undefined),它生成一个三元素数组并将undefined 分配给每个元素。

您如何将其推广到 N 个元素?考虑Array() 的工作原理,如下所示:

function Array() {
    if ( arguments.length == 1 &&
         'number' === typeof arguments[0] &&
         arguments[0] >= 0 && arguments &&
         arguments[0] < 1 << 32 ) {
        return [ … ];  // array of length arguments[0], generated by native code
    }
    var a = [];
    for (var i = 0; i < arguments.length; i++) {
        a.push(arguments[i]);
    }
    return a;
}

Since ECMAScript 5, Function.prototype.apply(thisArg, argsArray) 也接受一个鸭子类型的类数组对象作为其第二个参数。如果我们调用Array.apply(null, { length: N }),那么它将执行

function Array() {
    var a = [];
    for (var i = 0; i < /* arguments.length = */ N; i++) {
        a.push(/* arguments[i] = */ undefined);
    }
    return a;
}

现在我们有一个 N 元素数组,每个元素都设置为undefined。当我们在其上调用.map(callback, thisArg) 时,每个元素都会被设置为callback.call(thisArg, element, index, array) 的结果。因此,[undefined, undefined, …, undefined].map(Number.call, Number) 会将每个元素映射到(Number.call).call(Number, undefined, index, array),这与Number.call(undefined, index, array) 相同,正如我们之前观察到的,其计算结果为index。这样就完成了元素与其索引相同的数组。

为什么要麻烦Array.apply(null, {length: N}) 而不仅仅是Array(N)?毕竟,这两个表达式都会产生一个未定义元素的 N 元素数组。不同之处在于,在前一个表达式中,每个元素都明确设置为未定义,而在后一个表达式中,每个元素从未设置。根据.map()的文档:

callback 仅对具有赋值的数组索引调用;它不会为已删除或从未被赋值的索引调用。

因此,Array(N) 是不够的; Array(N).map(Number.call, Number) 将导致长度为 N 的未初始化数组。

兼容性

由于此技术依赖于 ECMAScript 5 中指定的 Function.prototype.apply() 的行为,因此它将在 ECMAScript 5 之前的浏览器(例如 Chrome 14 和 Internet Explorer 9)中使用 not work

【讨论】:

  • +1 表示聪明,但请注意这比原始 for 循环慢几个数量级:jsperf.com/array-magic-vs-for
  • 非常聪明——可能也太聪明了。利用Function.prototype.call 的第一个参数是this 对象直接映射到Array.prototype.map 的迭代器参数这一事实有一定的亮点。
  • 这真的非常聪明(近乎滥用 JS)。在我看来,这里真正重要的见解是map 对未分配值的特质。另一个版本(可能更清晰,尽管更长)是:Array.apply(null, { length: N }).map(function(element, index) { return index; })
  • @BenReich 更好(就 JS 滥用程度而言):Array.apply(null, new Array(N)).map(function(_,i) { return i; }) 或者,对于 es6 和箭头函数,甚至更短:Array.apply(null, new Array(N)).map((_,i) =&gt; i)
  • 如果这返回一个从 1 开始的数组,它实际上会回答 OP 的问题
【解决方案3】:

多种方式使用ES6

使用扩展运算符 (...) 和键方法

[ ...Array(N).keys() ].map( i => i+1);

填充/映射

Array(N).fill().map((_, i) => i+1);

Array.from

Array.from(Array(N), (_, i) => i+1)

Array.from 和 { length: N } hack

Array.from({ length: N }, (_, i) => i+1)

关于广义形式的注意事项

通过将i+1 更改为所需的表达式(例如i*2-i1+i*2i%2 等),上述所有形式都可以生成初始化为几乎任何所需值的数组。如果表达式可以用某个函数f来表达,那么第一种形式就变得简单了

[ ...Array(N).keys() ].map(f)

示例:

Array.from({length: 5}, (v, k) => k+1); 
// [1,2,3,4,5]

由于数组在每个位置上都使用undefined 进行初始化,因此v 的值将是undefined

展示所有表单的示例

let demo= (N) => {
  console.log(
    [ ...Array(N).keys() ].map(( i) => i+1),
    Array(N).fill().map((_, i) => i+1) ,
    Array.from(Array(N), (_, i) => i+1),
    Array.from({ length: N }, (_, i) => i+1)
  )
}

demo(5)

使用自定义初始化函数 f 的更通用示例,即

[ ...Array(N).keys() ].map((i) => f(i))

甚至更简单

[ ...Array(N).keys() ].map(f)

let demo= (N,f) => {
  console.log(
    [ ...Array(N).keys() ].map(f),
    Array(N).fill().map((_, i) => f(i)) ,
    Array.from(Array(N), (_, i) => f(i)),
    Array.from({ length: N }, (_, i) => f(i))
  )
}

demo(5, i=>2*i+1)

【讨论】:

  • 对从 0 开始的数组使用 k++
  • 如果要递增,不要使用k++,使用++k
  • 注意 Array.from 在 IE 中不被支持,除非你正在填充它。
  • 为了让 TS 编译器满意,考虑用 lodash 替换未使用的参数:Array.from({ length: 5 }, (_, k) => k + 1);
  • @bluejayke 我相信这个答案在我发表评论后已经被编辑过,但我专门谈论的是Array.from({length: 5}, (v, k) =&gt; k+1);,它确实只迭代一次。
【解决方案4】:

如果我得到你想要的,你想要一个数字数组1..n,以后可以循环访问。

如果这就是你所需要的,你可以这样做吗?

var foo = new Array(45); // create an empty array with length 45

那么当你想使用它时...(未优化,仅举例)

for(var i = 0; i < foo.length; i++){
  document.write('Item: ' + (i + 1) + ' of ' + foo.length + '<br/>'); 
}

例如如果你不需要在数组中存储任何东西,你只需要一个可以迭代的正确长度的容器......这可能更容易。

在此处查看实际操作:http://jsfiddle.net/3kcvm/

【讨论】:

  • 让您印象深刻的是,您设法比我更好地表达了我的问题,您确实是正确的,因为经过反思,我所需要的只是一组数字,以后可以循环遍历 :) 感谢您的回答。跨度>
  • @Godders:如果这是你要找的,为什么需要一个数组?一个简单的var n = 45; 然后从1..n 循环就可以了。
  • @Godders - 请注意,如果您想在创建数组后将其减小到长度 M,只需使用 foo.length = M --- 截断信息丢失。看到它在行动 ==> jsfiddle.net/ACMXp
  • 我真的不明白为什么这个答案甚至有赞成票......尤其是当 OP 本人同意这在上面的几个 cmets 中没有任何意义时,因为他本来可以做到 var n = 45;
  • @scunliffe:请注意,new Array(45); 不会“创建 45 个元素的数组”(与 [undefined,undefined,..undefined] 的含义相同)。而是“创建长度为 45 的空数组”([undefined x 45]),与var foo = []; foo.length=45; 相同。这就是为什么forEachmap 在这种情况下不适用的原因。
【解决方案5】:

数组天生就可以管理它们的长度。在遍历它们时,它们的索引可以保存在内存中并在此时引用。如果需要知道随机索引,可以使用indexOf方法。


这就是说,根据您的需要,您可能只想声明一个特定大小的数组:

var foo = new Array(N);   // where N is a positive integer

/* this will create an array of size, N, primarily for memory allocation, 
   but does not create any defined values

   foo.length                                // size of Array
   foo[ Math.floor(foo.length/2) ] = 'value' // places value in the middle of the array
*/


ES6

传播

利用扩展运算符 (...) 和 keys 方法,您可以创建一个大小为 N 的临时数组来生成索引,然后创建一个可以分配给变量的新数组:

var foo = [ ...Array(N).keys() ];

填充/映射

您可以先创建所需大小的数组,用 undefined 填充,然后使用 map 创建一个新数组,它将每个元素设置为索引。

var foo = Array(N).fill().map((v,i)=>i);

Array.from

这应该初始化为大小为 N 的长度并一次性填充数组。

Array.from({ length: N }, (v, i) => i)



代替 cmets 和混淆,如果您真的想从上面示例中的 1..N 中捕获值,有几个选项:

  1. 如果索引可用,您可以简单地将其加一(例如,++i)。
  2. 在不使用索引的情况下(可能是一种更有效的方法)是创建数组但使 N 代表 N+1,然后移出前面。

    所以如果你想要 100 个数字:

    let arr; (arr=[ ...Array(101).keys() ]).shift()
    




【讨论】:

  • 我相信当数字数组用于接收端无法处理的数据时,这很有用。 (就像一个只是替换值的 HTML 模板。)
  • 就像我说的,我需要用数字 1 到 10 填充下拉列表。仅此而已。有一个用例,我的用例。我就是这样找到这个页面的。因此,仅手动构建一个数组比我在这里看到的任何东西都简单。所以我的要求不是OP的要求。但我有我的答案。
  • @vol7ron 有一个用例,我也有一个。在有角度的分页中,我想在页脚中显示可点击的页面。因此,我使用 *ngFor="let p of pagesCounter" 在视图中循环元素。你有更好的解决方案吗?顺便说一句,请查看stackoverflow.com/questions/36354325/…
  • 这是错误的。所有示例都生成[0,..,n-1] 形式的数组,而问题针对[1,...,n]
  • @husayt 是的,你是对的;但是,这就是答案的重点(与所选答案一样)存储从 0..N 开始的数字并从 1..N+1 开始显示,方法是在演示文稿中添加 1
【解决方案6】:

在 ES6 中你可以这样做:

Array(N).fill().map((e,i)=&gt;i+1);

http://jsbin.com/molabiluwa/edit?js,console

编辑: 在您更新问题后,将 Array(45) 更改为 Array(N)

console.log(
  Array(45).fill(0).map((e,i)=>i+1)
);

【讨论】:

  • +1,因为它比讨厌的.join.splitversion 整体O好 - 但我仍然认为简陋的循环更好。
  • const gen = N =&gt; [...(function*(){let i=0;while(i&lt;N)yield i++})()]
  • 我不明白为什么.fill() 是必要的。我看到是在我对节点的 repl 进行测试时,但是由于Array(1)[0] === undefinedArray(1).fill(undefined) 中对 fill() 的调用有什么区别?
  • 对于其他感兴趣的人,Array(N) 和 Array(N).fill() 之间的区别解释得很好here
  • 一个循环中的数组填充和映射Array.from(Array(45), (_, i) =&gt; i + 1))
【解决方案7】:

使用非常流行的Underscore _.range method

// _.range([start], stop, [step])

_.range(10); // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11); // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5); // => [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1); //  => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0); // => []

【讨论】:

【解决方案8】:
function range(start, end) {
    var foo = [];
    for (var i = start; i <= end; i++) {
        foo.push(i);
    }
    return foo;
}

然后被调用

var foo = range(1, 5);

在 Javascript 中没有内置的方法来执行此操作,但如果您需要多次执行此操作,它是一个非常有效的实用函数。

编辑:在我看来,以下是一个更好的范围函数。也许只是因为我对 LINQ 有偏见,但我认为它在更多情况下更有用。您的里程可能会有所不同。

function range(start, count) {
    if(arguments.length == 1) {
        count = start;
        start = 0;
    }

    var foo = [];
    for (var i = 0; i < count; i++) {
        foo.push(start + i);
    }
    return foo;
}

【讨论】:

  • 我喜欢这个。如果您想更进一步,可以将其声明为 Array.prototype.range = function(start, end) { ... };。然后,您可以在任何 Array 对象上调用 range(x, y)。
  • 宁可让它成为Array 的方法,而不是Array.prototype,因为没有理由(甚至可能被认为相当愚蠢)在每个数组上都有这个方法。
  • Array.range(1, 5) 可能更合适,但写[].range(1, 5) 有点酷。
  • "宁愿让它成为 Array 的方法而不是 Array.prototype" - 有什么区别?你的意思是只在一个特定的数组上?
  • @pilau 正如亚当斯所说,它看起来很奇怪。如果它在原型上,你可以说foo = [1, 2, 3]; bar = foo.range(0, 10);。但这只是......令人困惑。 bar = Array.range(0, 10) 更加清晰明确。范围与实例无关,因此没有理由将其设为实例方法。
【解决方案9】:

在 v8 中填写 Array 的最快方法是:

[...Array(5)].map((_,i) => i);

结果将是:[0, 1, 2, 3, 4]

【讨论】:

  • 有没有办法不用额外的变量_
  • @bluejayke no :(
  • 苛刻,你知道.map的源代码是什么吗?我不确定它是否比 for 循环快,但如果不是,那么理论上我们可以定义属性并创建一个新的
【解决方案10】:

这个问题有很多复杂的答案,但很简单:

[...Array(255).keys()].map(x => x + 1)

另外,虽然上面写的很短(而且整洁),但我认为下面的写起来要快一些 (最大长度为:

127,Int8,

255,Uint8,

32,767,Int16,

65,535,Uint16,

2,147,483,647,Int32,

4,294,967,295,Uint32。

(基于max integer values),还有更多关于Typed Arrays):

(new Uint8Array(255)).map(($,i) => i + 1);

虽然这个解决方案也不是很理想,因为它创建了两个数组,并使用了额外的变量声明“$”(不确定使用这种方法有什么方法可以解决这个问题)。我认为以下解决方案是绝对最快的方法:

for(var i = 0, arr = new Uint8Array(255); i < arr.length; i++) arr[i] = i + 1;

此语句发出后的任何时候,您都可以在当前范围内简单地使用变量“arr”;

如果你想用它做一个简单的功能(通过一些基本的验证):

function range(min, max) {
    min = min && min.constructor == Number ? min : 0;
    !(max && max.constructor == Number && max > min) && // boolean statements can also be used with void return types, like a one-line if statement.
        ((max = min) & (min = 0));  //if there is a "max" argument specified, then first check if its a number and if its graeter than min: if so, stay the same; if not, then consider it as if there is no "max" in the first place, and "max" becomes "min" (and min becomes 0 by default)

    for(var i = 0, arr = new (
        max < 128 ? Int8Array : 
        max < 256 ? Uint8Array :
        max < 32768 ? Int16Array : 
        max < 65536 ? Uint16Array :
        max < 2147483648 ? Int32Array :
        max < 4294967296 ? Uint32Array : 
        Array
    )(max - min); i < arr.length; i++) arr[i] = i + min;
    return arr;
}



//and you can loop through it easily using array methods if you want
range(1,11).forEach(x => console.log(x));

//or if you're used to pythons `for...in` you can do a similar thing with `for...of` if you want the individual values:
for(i of range(2020,2025)) console.log(i);

//or if you really want to use `for..in`, you can, but then you will only be accessing the keys:

for(k in range(25,30)) console.log(k);

console.log(
    range(1,128).constructor.name,
    range(200).constructor.name,
    range(400,900).constructor.name,
    range(33333).constructor.name,
    range(823, 100000).constructor.name,
    range(10,4) // when the "min" argument is greater than the "max", then it just considers it as if there is no "max", and the new max becomes "min", and "min" becomes 0, as if "max" was never even written
);

所以,有了上面的功能,上面的超慢“简单单行”变成了超快,甚至更短:

range(1,14000);

【讨论】:

  • @JVG 但不是为了更快的功能?
  • 完全正确。这是每个人都在寻找的这种简单的班轮!
  • @supersan 虽然它超级慢 :)
  • 现代 javascript 和新的 fill 方法:Array(255).fill(0,0,255)
  • @cacoder 有多快,它创建了多少个数组以及多少次迭代?
【解决方案11】:

使用 ES2015/ES6 扩展运算符

[...Array(10)].map((_, i) => i + 1)

console.log([...Array(10)].map((_, i) =&gt; i + 1))

【讨论】:

  • i + 1++i 更有意义。
【解决方案12】:

你可以用这个:

new Array(/*any number which you want*/)
    .join().split(',')
    .map(function(item, index){ return ++index;})

例如

new Array(10)
    .join().split(',')
    .map(function(item, index){ return ++index;})

将创建以下数组:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

【讨论】:

  • 另外,为什么不new Array(10).join().split(',').map(function() {return ++arguments[1]});
  • @Murplyx 对于某些情况下带有参数的函数不会被 JS 引擎优化(即使对于 V8 也是如此,请参阅jsperf.com/arguments-vs-array-argument/2
  • 这是一个有趣的解决方案,但它完全不切实际 - 必须解析数组 3 次(一次到 join,一次到 split,一次是为了这个东西您实际上想要这样做)只是不好 - 我知道它们似乎由于某种原因已经失宠,但是简单地使用一个好的老式 loop 会好得多!
【解决方案13】:

如果你碰巧像我一样在你的应用程序中使用d3.js,D3 提供了一个帮助函数来为你做这件事。

所以要得到一个从 0 到 4 的数组,就这么简单:

d3.range(5)
[0, 1, 2, 3, 4]

并按照您的要求获取从 1 到 5 的数组:

d3.range(1, 5+1)
[1, 2, 3, 4, 5]

查看this tutorial 了解更多信息。

【讨论】:

  • 这条评论让我想到在 RamdaJS 中查找 the range() function,这恰好是我在当前项目中使用的 JS 库。完美。
【解决方案14】:

这可能是生成数字数组的最快方法

最短的

var a=[],b=N;while(b--)a[b]=b+1;

内联

var arr=(function(a,b){while(a--)b[a]=a;return b})(10,[]);
//arr=[0,1,2,3,4,5,6,7,8,9]

如果你想从 1 开始

var arr=(function(a,b){while(a--)b[a]=a+1;return b})(10,[]);
//arr=[1,2,3,4,5,6,7,8,9,10]

想要一个功能?

function range(a,b,c){c=[];while(a--)c[a]=a+b;return c}; //length,start,placeholder
var arr=range(10,5);
//arr=[5,6,7,8,9,10,11,12,13,14]

为什么?

  1. while 是最快的循环

  2. 直接设置比push

  3. []new Array(10)

  4. 很短...看第一个代码。然后看看这里的所有其他功能。

如果你喜欢就不能没有for

for(var a=[],b=7;b>0;a[--b]=b+1); //a=[1,2,3,4,5,6,7]

for(var a=[],b=7;b--;a[b]=b+1); //a=[1,2,3,4,5,6,7]

【讨论】:

  • 最好用基准来支持这些声明。试试jsperf.com
  • lol jsperf ...请马特只是因为你不喜欢我的回答停止投票给我的其他人...stackoverflow.com/a/18344296/2450730 ...使用console.time()或它的名称...不是 jsperf。
  • 仅供参考:正如 John Reisig 几年前首次发布的那样 - 在某些平台(意味着 windows:P)上,每 16 毫秒将时间馈送到浏览器一次。在多任务环境中测量执行时间还存在其他问题。 jsperf.com 已经实现了运行测试,因此它们在统计上是正确的。可以运行 console.time() 来获得直觉,但为了证明,您需要 jsperf.com 并且它会显示来自其他人(不同硬件等)的跨浏览器结果
  • @cocco 这是不正确的:var a=[],b=N;while(b--){a[b]=a+1};
  • @cocco — while 并不总是 比其他循环快。在某些浏览器中,递减的 while 循环比 for 循环慢得多,你不能像这样对 javascript 性能做出一般性的陈述,因为有很多实现有很多不同的优化。但是,总的来说,我喜欢您的方法。 ;-)
【解决方案15】:

如果你使用的是lodash,你可以使用_.range

_.range([start=0], end, [step=1])

创建一个数字数组 (正面和/或负面)从开始到,但不是 包括,结束。如果指定负开始,则使用 -1 步长 没有终点或步骤。如果未指定 end,则设置为 start 与 start 然后设置为 0。

例子:

_.range(4);
// ➜ [0, 1, 2, 3]

_.range(-4);
// ➜ [0, -1, -2, -3]

_.range(1, 5);
// ➜ [1, 2, 3, 4]

_.range(0, 20, 5);
// ➜ [0, 5, 10, 15]

_.range(0, -4, -1);
// ➜ [0, -1, -2, -3]

_.range(1, 4, 0);
// ➜ [1, 1, 1]

_.range(0);
// ➜ []

【讨论】:

  • 这是一个相当大的if
【解决方案16】:

填写Array的新方法是:

const array = [...Array(5).keys()]
console.log(array)

结果将是:[0, 1, 2, 3, 4]

【讨论】:

  • 这是一个非常好的答案,虽然从技术上讲问题来自 1-N,而不是 0-(N-1)
  • 也许我们可以使用 rest 运算符 (...) 像 const [, ...array] = Array(5).keys();
【解决方案17】:

性能

今天 2020.12.11,我在 Chrome v87、Safari v13.1.2 和 Firefox v83 上对 MacOs HighSierra 10.13.6 进行测试,以获取所选解决方案。

结果

适用于所有浏览器

  • 解决方案O(基于while)最快(除了Firefox for big N - 但在那里很快)
  • 解决方案 T 在 Firefox for big N 上最快
  • 解决方案 M,P 对于小 N 来说很快
  • 解决方案 V (lodash) 对于大 N 来说很快
  • 解决方案 W,X 对于小 N 来说很慢
  • 解决方案 F 很慢

详情

我执行 2 个测试用例:

  • 对于小 N = 10 - 你可以运行它HERE
  • 对于大 N = 1000000 - 你可以运行它HERE

下面 sn-p 展示了所有经过测试的解决方案A B C D E F G H I J K L M N O P Q R S T U V W X

function A(N) {
  return Array.from({length: N}, (_, i) => i + 1)
}

function B(N) {
  return Array(N).fill().map((_, i) => i+1);
}

function C(N) {
  return Array(N).join().split(',').map((_, i) => i+1 );
}

function D(N) {
  return Array.from(Array(N), (_, i) => i+1)
}

function E(N) {
  return Array.from({ length: N }, (_, i) => i+1)
}

function F(N) {
  return Array.from({length:N}, Number.call, i => i + 1)
}

function G(N) {
  return (Array(N)+'').split(',').map((_,i)=> i+1)
}

function H(N) {
  return [ ...Array(N).keys() ].map( i => i+1);
}

function I(N) {
  return [...Array(N).keys()].map(x => x + 1);
}

function J(N) {
  return [...Array(N+1).keys()].slice(1)
}

function K(N) {
  return [...Array(N).keys()].map(x => ++x);
}

function L(N) {
  let arr; (arr=[ ...Array(N+1).keys() ]).shift();
  return arr;
}

function M(N) {
  var arr = [];
  var i = 0;

  while (N--) arr.push(++i);

  return arr; 
}

function N(N) {
  var a=[],b=N;while(b--)a[b]=b+1;
  return a;
}

function O(N) {
  var a=Array(N),b=0;
  while(b<N) a[b++]=b;
  return a;
}

function P(N) {
  var foo = [];
  for (var i = 1; i <= N; i++) foo.push(i);
  return foo;
}

function Q(N) {
  for(var a=[],b=N;b--;a[b]=b+1);
  return a;
}

function R(N) {
  for(var i,a=[i=0];i<N;a[i++]=i);
  return a;
}

function S(N) {
    let foo,x;
    for(foo=[x=N]; x; foo[x-1]=x--);
  return foo;
}

function T(N) {
  return new Uint8Array(N).map((item, i) => i + 1);
}

function U(N) {
  return '_'.repeat(5).split('').map((_, i) => i + 1);
}

function V(N) {
  return _.range(1, N+1);
}

function W(N) {
  return [...(function*(){let i=0;while(i<N)yield ++i})()]
}

function X(N) {
  function sequence(max, step = 1) {
    return {
      [Symbol.iterator]: function* () {
        for (let i = 1; i <= max; i += step) yield i
      }
    }
  }

  return [...sequence(N)];
}


[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X].forEach(f=> {
  console.log(`${f.name} ${f(5)}`);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"> </script>
  
This shippet only presents functions used in performance tests - it not perform tests itself!

以下是 chrome 的示例结果

【讨论】:

    【解决方案18】:

    使用 ES6 你可以做到:

    // `n` is the size you want to initialize your array
    // `null` is what the array will be filled with (can be any other value)
    Array(n).fill(null)
    

    【讨论】:

    • 由于数组的值实际上是使用此解决方案填充的,mapforEach 将起作用。
    【解决方案19】:

    https://stackoverflow.com/a/49577331/8784402

    有三角洲

    对于javascript

    最小的单线
    [...Array(N)].map((v, i) => from + i * step);
    

    示例和其他替代方法

    Array.from(Array(10).keys()).map(i => 4 + i * 2);
    //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
    
    [...Array(10).keys()].map(i => 4 + i * -2);
    //=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
    
    Array(10).fill(0).map((v, i) => 4 + i * 2);
    //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
    
    Array(10).fill().map((v, i) => 4 + i * -2);
    //=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
    
    [...Array(10)].map((v, i) => 4 + i * 2);
    //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
    
    范围函数
    const range = (from, to, step) =>
      [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
    
    range(0, 9, 2);
    //=> [0, 2, 4, 6, 8]
    
    // can also assign range function as static method in Array class (but not recommended )
    Array.range = (from, to, step) =>
      [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
    
    Array.range(2, 10, 2);
    //=> [2, 4, 6, 8, 10]
    
    Array.range(0, 10, 1);
    //=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    Array.range(2, 10, -1);
    //=> []
    
    Array.range(3, 0, -1);
    //=> [3, 2, 1, 0]
    
    作为迭代器
    class Range {
      constructor(total = 0, step = 1, from = 0) {
        this[Symbol.iterator] = function* () {
          for (let i = 0; i < total; yield from + i++ * step) {}
        };
      }
    }
    
    [...new Range(5)]; // Five Elements
    //=> [0, 1, 2, 3, 4]
    [...new Range(5, 2)]; // Five Elements With Step 2
    //=> [0, 2, 4, 6, 8]
    [...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
    //=>[10, 8, 6, 4, 2]
    [...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
    //=> [-10, -12, -14, -16, -18]
    
    // Also works with for..of loop
    for (i of new Range(5, -2, 10)) console.log(i);
    // 10 8 6 4 2
    
    仅作为发电机
    const Range = function* (total = 0, step = 1, from = 0) {
      for (let i = 0; i < total; yield from + i++ * step) {}
    };
    
    Array.from(Range(5, -2, -10));
    //=> [-10, -12, -14, -16, -18]
    
    [...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
    //=> [-10, -12, -14, -16, -18]
    
    // Also works with for..of loop
    for (i of Range(5, -2, 10)) console.log(i);
    // 10 8 6 4 2
    
    // Lazy loaded way
    const number0toInf = Range(Infinity);
    number0toInf.next().value;
    //=> 0
    number0toInf.next().value;
    //=> 1
    // ...
    

    From-To with steps/delta

    使用迭代器
    class Range2 {
      constructor(to = 0, step = 1, from = 0) {
        this[Symbol.iterator] = function* () {
          let i = 0,
            length = Math.floor((to - from) / step) + 1;
          while (i < length) yield from + i++ * step;
        };
      }
    }
    [...new Range2(5)]; // First 5 Whole Numbers
    //=> [0, 1, 2, 3, 4, 5]
    
    [...new Range2(5, 2)]; // From 0 to 5 with step 2
    //=> [0, 2, 4]
    
    [...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
    //=> [10, 8, 6]
    
    使用生成器
    const Range2 = function* (to = 0, step = 1, from = 0) {
      let i = 0,
        length = Math.floor((to - from) / step) + 1;
      while (i < length) yield from + i++ * step;
    };
    
    [...Range2(5, -2, 10)]; // From 10 to 5 with step -2
    //=> [10, 8, 6]
    
    let even4to10 = Range2(10, 2, 4);
    even4to10.next().value;
    //=> 4
    even4to10.next().value;
    //=> 6
    even4to10.next().value;
    //=> 8
    even4to10.next().value;
    //=> 10
    even4to10.next().value;
    //=> undefined
    

    对于打字稿

    class _Array<T> extends Array<T> {
      static range(from: number, to: number, step: number): number[] {
        return Array.from(Array(Math.floor((to - from) / step) + 1)).map(
          (v, k) => from + k * step
        );
      }
    }
    _Array.range(0, 9, 1);
    

    【讨论】:

    • 这是我见过的关于堆栈溢出最难的 flex
    【解决方案20】:

    最终总结报告 .. Drrruummm Rolll -

    这是最短的代码来生成一个大小为 N(这里是 10)的数组不使用 ES6Cocco 上面的版本很接近,但不是最短的。

    (function(n){for(a=[];n--;a[n]=n+1);return a})(10)
    

    但是这个代码高尔夫(以最少的源代码字节解决特定问题的竞赛)的无可争议的赢家Niko Ruotsalainen。使用数组构造器和 ES6 扩展运算符。 (大部分 ES6 语法都是有效的 typeScript,但以下不是。所以在使用时要谨慎)

    [...Array(10).keys()]
    

    【讨论】:

    • 为什么要投反对票?长长的答案列表难以理解,所以想总结一下。
    • 这不是0-10吗? [...Array(10).keys()]
    • Webstorm 建议(new Array(10)).keys(),对吗?
    • (new Array(10)).keys() ,返回 ArrayIterator {} ,而不是数组
    • 这会创建一个全局变量a。循环应该是for(var a=[];n--;a[n]=n+1)
    【解决方案21】:

    非常简单且容易准确地生成 1 - N

    const [, ...result] = Array(11).keys();
    
    console.log('Result:', result);

    【讨论】:

      【解决方案22】:

      在 ES6 中还有另一种方式,使用 Array.from,它接受 2 个参数,第一个是 arrayLike(在本例中为具有 length 属性的对象),第二个是映射函数(在本例中我们映射项目到它的索引)

      Array.from({length:10}, (v,i) => i)
      

      这更短,可用于生成偶数等其他序列

      Array.from({length:10}, (v,i) => i*2)
      

      这也比大多数其他方式具有更好的性能,因为它只在数组中循环一次。 检查代码段以进行一些比较

      // open the dev console to see results
      
      count = 100000
      
      console.time("from object")
      for (let i = 0; i<count; i++) {
        range = Array.from({length:10}, (v,i) => i )
      }
      console.timeEnd("from object")
      
      console.time("from keys")
      for (let i =0; i<count; i++) {
        range = Array.from(Array(10).keys())
      }
      console.timeEnd("from keys")
      
      console.time("apply")
      for (let i = 0; i<count; i++) {
        range = Array.apply(null, { length: 10 }).map(function(element, index) { return index; })
      }
      console.timeEnd("apply")

      【讨论】:

      • 嘿,这很整洁,我喜欢它。但是它不会返回 OP 期望的结果。为此,它需要写成Array.from({length:N}, (v,i) =&gt; i+1)
      • 这些neato hacks 仍然是5-10x slower than a good old for loop
      【解决方案23】:

      使用来自 ES6 标准的新 Array 方法和 =&gt; 函数语法(撰写本文时仅限 Firefox)。

      undefined填充孔:

      Array(N).fill().map((_, i) => i + 1);
      

      Array.from 将“洞”变成undefined,所以Array.map 可以按预期工作:

      Array.from(Array(5)).map((_, i) => i + 1)
      

      【讨论】:

      • 同样,你也可以在 ES6 中做如下操作:Array.from({length: N}, (v, k) =&gt; k).
      • Xappli 的方法是首选: Array.from 是为几乎这种确切的场景创建的,它意味着一个映射回调。对于想要在类似数组的东西上使用数组方法的一般问题,这是一个很好的解决方案,而无需使用像 Array.prototype.map.call 这样的冗长方法,例如对于从 document.querySelectorAll 返回的 NodeLists。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
      • 我正在权衡这个与下划线范围语法,范围读起来更好。
      • 技术上不是Array.from 将稀疏值变成未定义的。而Array(5) 被称为参数对象,该对象又将稀疏值解释为未定义值:)
      【解决方案24】:

      在 ES6 中:

      Array.from({length: 1000}, (_, i) => i).slice(1);
      

      或者更好(没有额外的变量 _ 和额外的 slice 调用):

      Array.from({length:1000}, Number.call, i => i + 1)
      

      或者,如果您的列表少于 256 个结果,您可以使用 Uint8Array(或者您可以使用其他 Uint 列表,具体取决于列表的长度,例如 Uint16 表示最大数量为 65535,或 Uint32最多为 4294967295 等。Officially, these typed arrays were only added in ES6 though)。例如:

      Uint8Array.from({length:10}, Number.call, i => i + 1)
      

      ES5:

      Array.apply(0, {length: 1000}).map(function(){return arguments[1]+1});
      

      另外,在 ES5 中,对于 map 函数(如上面 ES6 中 Array.from 函数的第二个参数),您可以使用 Number.call

      Array.apply(0,{length:1000}).map(Number.call,Number).slice(1)
      

      或者,如果您在这里也反对.slice,您可以执行上述(来自 ES6)的 ES5 等效项,例如:

      Array.apply(0,{length:1000}).map(Number.call, Function("i","return i+1"))
      

      【讨论】:

        【解决方案25】:

        快速

        这个解决方案可能是最快的,它的灵感来自 lodash _.range 函数(但我的更简单更快)

        let N=10, i=0, a=Array(N);
        
        while(i<N) a[i++]=i;
        
        
        
        console.log(a);

        相对于当前 (2020.12.11) 基于while/for 的现有答案的性能优势

        • 内存由a=Array(N)在开头分配一次
        • 使用增加索引i++ - 看起来比减少索引i-- 快约30%(可能是因为CPU 高速缓存在前向更快)

        this answer 中进行了 20 多种其他解决方案的速度测试

        【讨论】:

          【解决方案26】:

          Array(...Array(9)).map((_, i) => i);
          
          console.log(Array(...Array(9)).map((_, i) => i))

          【讨论】:

          • 不错!也可以更简洁地写成[...Array(9)].map((_, i) =&gt; i)
          【解决方案27】:
          for(var i,a=[i=0];i<10;a[i++]=i);
          

          a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

          【讨论】:

          • 真的很棒!发送!
          【解决方案28】:

          目前看来,这个相当完整的答案列表中唯一没有的风味是具有生成器的风味;为了解决这个问题:

          const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
          

          可以这样使用:

          gen(4) // [0,1,2,3]
          

          这样做的好处是您不必增加...要从@igor-shubin 给出的答案中获得灵感,您可以非常轻松地创建一个随机数组:

          const gen = N => [...(function*(){let i=0;
            while(i++<N) yield Math.random()
          })()]
          

          而不是像 冗长 操作昂贵的东西:

          const slow = N => new Array(N).join().split(',').map((e,i)=>i*5)
          // [0,5,10,15,...]
          

          你可以这样做:

          const fast = N => [...(function*(){let i=0;while(i++<N)yield i*5})()]
          

          【讨论】:

            【解决方案29】:
            Array(8).fill(0).map(Number.call, Number)
            

            窃取 Igors Number.call 技巧,但使用 fill() 稍微缩短。仅适用于 ES6 及更高版本。

            【讨论】:

            • 这将创建从 0 到 7 而不是从 1 到 8 的数字范围
            • 简称:Array(5).fill().map((_, i) =&gt; i+1)
            【解决方案30】:

            您可以使用 Es6 中的数组填充和映射;就像一些人在他们为这个问题给出的答案中建议的那样。下面是几个例子:

            Example-One: Array(10).fill(0).map((e,i)=>i+1)
            
            Result-One: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
            
            Example-Two: Array(100/10).fill(0).map((e,i)=>(i*10)+10)
            
            Result-Two:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
            
            

            我更喜欢这个,因为我觉得它简单明了。

            【讨论】:

              猜你喜欢
              • 2015-12-24
              • 2015-05-12
              • 2019-09-03
              • 1970-01-01
              • 1970-01-01
              • 2021-07-20
              • 2023-02-01
              • 1970-01-01
              相关资源
              最近更新 更多