ChatGPT解决这个技术问题 Extra ChatGPT

如何创建一个包含 1...N 的数组

我正在寻找下面的任何替代方法来创建一个包含 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 中用于 glob 模式
另一种方法是这样的: Array.from({length : 10}, (_, v) => v)
@SahilGupta 几乎。如果我们想要 1 到 10,我们需要加 1,例如:Array.from({length : 10}, (_, v) => v+1)
将 foo 定义为 object {} 而不是数组,然后使用 foo[i] = i; 添加您自己的索引;

A
Audwin Oyong

在 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 => x++);) 以从 1 开始
只需将 map(x => x++) 更改为 map(x => ++x),因为在返回值之后会发生优先级递增 :)
呃什么!?当您可以简单地 slice 时,为什么还要 map[...Array(N+1).keys()].slice(1)
或者不要使用 keys 并且只有 1 个地图 -> Array.from(Array(10)).map((e,i)=>i+1)
或者不使用键和映射,只需将映射函数传递给 from Array.from(Array(10), (e,i)=>i+1)
2
200_success

你可以这样做:

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)

result: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915958732, 0.16363654541783035]

解释

首先,请注意 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 5Function.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()的文档:

回调仅针对已分配值的数组索引调用;对于已被删除或从未被赋值的索引,它不会被调用。

因此,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) => i)
如果这返回一个从 1 开始的数组,它实际上会回答 OP 的问题
h
husayt

使用 ES6 的多种方式

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

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

填充/贴图

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

数组.from

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

Array.from 和 { 长度:N } 破解

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

展示所有表格的示例

让 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({ 长度: N }, (_, i) => i+1) ) } 演示(5)

具有自定义初始化函数 f 的更通用示例

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

甚至更简单

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

让 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({ 长度: N }, (_, i) => f(i )) ) } 演示(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) => k+1);,它确实只迭代一次。
u
user229044

如果我得到你想要的,你想要一个数字数组 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 本人同意上面的一些评论没有任何意义时,因为他本来可以做到 var n = 45;
@scunliffe:请注意,new Array(45); 不会“创建 45 个元素的数组”(与 [undefined,undefined,..undefined] 的含义相同)。而是“创建长度 = 45 的空数组”([undefined x 45]),与 var foo = []; foo.length=45; 相同。这就是 forEachmap 在这种情况下不适用的原因。
v
vol7ron

数组天生就管理它们的长度。在遍历它们时,它们的索引可以保存在内存中并在此时引用。如果需要知道随机索引,可以使用 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);

数组.from

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

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

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

如果索引可用,您可以简单地将其加一(例如,++i)。在不使用索引的情况下(可能是一种更有效的方法)是创建数组但使 N 代表 N+1,然后移出前面。所以如果你想要 100 个数字:让 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
m
mplungjan

在 ES6 中,你可以这样做:

Array(N).fill().map((e,i)=>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.split版本要好一个整体O - 但我仍然认为简陋的循环更好。
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
您不需要将 arg 添加到 .fill()
我不明白为什么需要 .fill()。我看到是在我对节点的 repl 进行测试时,但由于 Array(1)[0] === undefined,在 Array(1).fill(undefined) 中对 fill() 的调用有什么不同?
对于其他感兴趣的人,Array(N) 和 Array(N).fill() 之间的区别解释得很好here
E
Evan

使用非常流行的 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); // => []

惊人的。给我看一个不使用下划线的大型项目......
I
Ian Henry
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) 更加清晰明确。范围与实例无关,因此没有理由将其设为实例方法。
M
Moha the almighty camel

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

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

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


有没有办法在没有额外变量_的情况下做到这一点
@bluejayke 没有 :(
苛刻,你知道.map的源代码是什么吗?我不确定它是否比 for 循环快,但如果不是,那么理论上我们可以定义属性并创建一个新的
B
B''H Bi'ezras -- Boruch Hashem

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

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

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

127,国际8,

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”;

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

函数范围(最小值,最大值){ min = min && min.constructor == Number ?最小值:0; !(max && max.constructor == Number && max > min) && // 布尔语句也可以与 void 返回类型一起使用,例如单行 if 语句。 ((最大值 = 最小值) & (最小值 = 0)); //如果指定了“max”参数,那么首先检查它是否是一个数字,如果它大于min:如果是,保持不变;如果不是,那么首先将其视为没有“max”,并且“max”变为“min”(默认情况下min变为0) 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;返回 arr; } //如果需要 range(1,11).forEach(x => console.log(x)); 可以使用数组方法轻松循环//或者如果你习惯了 python `for...in`,如果你想要单独的值,你可以用 `for...of` 做类似的事情:for(i of range(2020,2025)) 控制台.log(i); //或者如果你真的想使用`for..in`,你可以,但是你只会访问键: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) // 当“min”参数大于“max”时,就认为没有“max”,新的max变成“min”,“min”变成 0,就好像“max”从来没有写过);

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

range(1,14000);

@JVG 但不是为了更快的功能?
非常正确。这是每个人都在寻找的简单的一个班轮!
@supersan 虽然它超级慢:)
具有新 fill 方法的现代 javascript:Array(255).fill(0,0,255)
@cacoder 它有多快,它创建了多少个数组以及多少次迭代?
V
Vlad Bezden

使用 ES2015/ES6 扩展运算符

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

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


i + 1++i 更有意义。
A
Abdennour TOUMI

你可以使用这个:

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
T
Tyler Rick

如果您碰巧像我一样在您的应用程序中使用 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 库。完美的。
J
Jeff Huijsmans

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

最短的

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]

为什么?

while 是最快的循环 Direct setting is faster than push [] is faster than new Array(10) 它很短......看第一个代码。然后看看这里的所有其他功能。

如果你喜欢不能没有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
大声笑 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 性能做出一般性陈述,因为有如此多的实现具有如此多的不同优化。但是,总的来说,我喜欢您的方法。 ;-)
y
yivi

表现

今天 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 很慢

https://i.stack.imgur.com/EE26M.png

细节

我执行 2 个测试用例:

对于小 N = 10 - 你可以在这里运行它

对于大 N = 1000000 - 你可以在这里运行它

下面的代码段展示了所有经过测试的解决方案 A B C D E F G H I J K L M N {15 } 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); } 函数 J(N) { 返回 [...Array(N+1).keys()].slice(1) } 函数 K(N) { 返回 [...Array(N).keys()]。地图(x => ++x); } 函数 L(N) { 让 arr; (arr=[ ...Array(N+1).keys() ]).shift();返回 arr; } 函数 M(N) { var arr = [];变量 i = 0;而 (N--) arr.push(++i);返回 arr; } 函数 N(N) { var a=[],b=N;while(b--)a[b]=b+1;返回一个; } 函数 O(N) { var a=Array(N),b=0;而(b i + 1); } function U(N) { return '_'.repeat(5).split('').map((_, i) => i + 1); } 函数 V(N) { 返回 _.range(1, N+1); } function W(N) { return [...(function*(){let i=0;while(i { console.log(`${f.name} ${f(5)}`); }) 这个 Shippet 只提供性能测试中使用的功能!

这是 chrome 的示例结果

https://i.stack.imgur.com/Sv1uE.png


那是一件作品!做得好!
k
k0pernikus

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

_.range([start=0], end, [step=1]) 创建一个从 start 到但不包括 end 的数字数组(正数和/或负数)。如果指定负开始而没有结束或步骤,则使用 -1 的步骤。如果未指定 end,则设置为从 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
а
аlex dykyі

填充 Array 的新方法是:

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

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


这是一个非常好的答案,尽管从技术上讲问题来自 1-N,而不是 0-(N-1)
也许我们可以使用像 const [, ...array] = Array(5).keys(); 这样的 rest 运算符 (...);
佚名

使用 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 将起作用。
n
nkitku

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

从 - 到步骤/增量

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
C
Community

最终总结报告.. 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吗? [...数组(10).keys()]
Webstorm 建议 (new Array(10)).keys(),对吗?
(new Array(10)).keys() ,返回 ArrayIterator {} ,而不是数组
这将创建一个全局变量 a。循环应该是 for(var a=[];n--;a[n]=n+1)
y
yivi

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

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


g
gafi

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

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

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

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

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

// 打开开发控制台查看结果 count = 100000 console.time("from object") for (let i = 0; i i) } console.timeEnd("from object") console.time("from keys") for (let i =0; i


嘿,这很整洁,我喜欢它。但是它不会返回 OP 期望的结果。为此,它需要写成 Array.from({length:N}, (v,i) => i+1)
这些neato hack 仍然是5-10x slower than a good old for loop
s
szymzet

使用来自 ES6 标准的新 Array 方法和 => 函数语法(在撰写本文时仅限 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) => k)
Xappli 的方法是首选: Array.from 几乎是为这种确切的场景创建的,它暗示了一个映射回调。对于想要在类似数组的东西上使用数组方法的一般问题,这是一个很好的解决方案,而无需使用像 Array.prototype.map.call 这样的冗长方法,例如对于从 document.querySelectorAll 返回的 NodeLists。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
我正在权衡这与下划线范围语法,范围读起来更好。
从技术上讲,它不是 Array.from 将稀疏值变成未定义的。而是 Array(5) 被称为参数对象,该对象又将稀疏值解释为未定义值:)
K
Kamil Kiełczewski

快速地

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

令 N=10, i=0, a=Array(N);而(i

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

内存由 a=Array(N) 在开始时分配一次

使用增加索引 i++ - 看起来比减少索引 i 快大约 30% - (可能是因为 CPU 高速缓存在前向更快)

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


B
B''H Bi'ezras -- Boruch Hashem

在 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,您可以执行上述 ES5 等效项(来自 ES6),例如:

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

а
аlex dykyі

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


好的!也可以更简洁地写成 [...Array(9)].map((_, i) => i)
S
SammieFox
for(var i,a=[i=0];i<10;a[i++]=i);

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


非常棒!发送!
R
Robin

似乎目前不在这个相当完整的答案列表中的唯一风味是具有生成器的风味。所以要解决这个问题:

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})()]

A
AP.
Array(8).fill(0).map(Number.call, Number)

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


这将创建从 0 到 7 而不是从 1 到 8 的数字范围
更短的只是:Array(5).fill().map((_, i) => i+1)
如果你想给个位数加 0 var foo = Array(52).fill().map((v,i)=> { let r = (i+1).toString().length == 1 ? "0" + (i + 1).toString() : (i + 1).toString(); return r });
O
Oluwagbemi Kadri

您可以使用 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]

我更喜欢这个,因为我发现它简单明了而且更容易。