我正在寻找下面的任何替代方法来创建一个包含 1 到 N 的 JavaScript 数组,其中 N 仅在运行时已知。
var foo = [];
for (var i = 1; i <= N; i++) {
foo.push(i);
}
对我来说,感觉应该有一种方法可以在没有循环的情况下做到这一点。
在 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]
你可以这样做:
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 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()
的文档:
回调仅针对已分配值的数组索引调用;对于已被删除或从未被赋值的索引,它不会被调用。
因此,Array(N)
是不充分的; Array(N).map(Number.call, Number)
将导致长度为 N 的未初始化数组。
兼容性
由于此技术依赖于 ECMAScript 5 中指定的 Function.prototype.apply()
行为,因此它将在 ECMAScript 5 之前的浏览器(例如 Chrome 14 和 Internet Explorer 9)中not work。
Function.prototype.call
的第一个参数是 this
对象直接映射到 Array.prototype.map
的迭代器参数这一事实具有一定的优势。
map
对未分配值的特质。另一个版本(可能更清晰,尽管更长)是:Array.apply(null, { length: N }).map(function(element, index) { return index; })
Array.apply(null, new Array(N)).map(function(_,i) { return i; })
或者,对于 es6 和箭头函数,甚至更短:Array.apply(null, new Array(N)).map((_,i) => i)
使用 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
、-i
、1+i*2
、i%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)
k++
,使用 ++k
。
Array.from({length: 5}, (v, k) => k+1);
,它确实只迭代一次。
如果我得到你想要的,你想要一个数字数组 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/
var n = 45;
然后从 1..n
循环就可以了。
foo.length = M
--- 截断信息丢失。看到它在行动==> jsfiddle.net/ACMXp
var n = 45;
。
new Array(45);
不会“创建 45 个元素的数组”(与 [undefined,undefined,..undefined]
的含义相同)。而是“创建长度 = 45 的空数组”([undefined x 45]
),与 var foo = []; foo.length=45;
相同。这就是 forEach
和 map
在这种情况下不适用的原因。
数组天生就管理它们的长度。在遍历它们时,它们的索引可以保存在内存中并在此时引用。如果需要知道随机索引,可以使用 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()
[0,..,n-1]
形式的数组,而问题是针对 [1,...,n]
在 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) );
.join.split
版本要好一个整体大O - 但我仍然认为简陋的循环更好。
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
.fill()
.fill()
。我看到是在我对节点的 repl 进行测试时,但由于 Array(1)[0] === undefined
,在 Array(1).fill(undefined)
中对 fill() 的调用有什么不同?
使用非常流行的 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); // => []
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
而不是 Array.prototype
的方法,因为没有理由(甚至可能被认为相当愚蠢)在每个数组上都有这个方法。
Array.range(1, 5)
可能更合适,但写 [].range(1, 5)
有一些很酷的地方。
foo = [1, 2, 3]; bar = foo.range(0, 10);
。但这只是......令人困惑。 bar = Array.range(0, 10)
更加清晰明确。范围与实例无关,因此没有理由将其设为实例方法。
在 v8 中填充 Array
的最快方法是:
[...Array(5)].map((_,i) => i);
结果将是:[0, 1, 2, 3, 4]
这个问题有很多复杂的答案,但很简单:
[...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);
fill
方法的现代 javascript:Array(255).fill(0,0,255)
使用 ES2015/ES6 扩展运算符
[...Array(10)].map((_, i) => i + 1)
console.log([...Array(10)].map((_, i) => i + 1))
i + 1
比 ++i
更有意义。
你可以使用这个:
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]});
?
join
,一次到 split
,一次用于您真正想做的事情)只是不好 - 我知道它们似乎由于某种原因已经失宠,但最好还是简单地使用一个好的老式 loop!
如果您碰巧像我一样在您的应用程序中使用 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 了解更多信息。
这可能是生成数字数组的最快方法
最短的
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]
console.time()
来获得直觉,但为了证明,您需要 jsperf.com 并且它会显示来自其他人(不同硬件等)的跨浏览器结果
var a=[],b=N;while(b--){a[b]=a+1};
表现
今天 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
这是 chrome 的示例结果
https://i.stack.imgur.com/Sv1uE.png
如果您使用的是 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
填充 Array
的新方法是:
const array = [...Array(5).keys()] console.log(array)
结果将是:[0, 1, 2, 3, 4]
使用 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)
map
和 forEach
将起作用。
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);
最终总结报告.. Drrruummm Rolll -
这是最短的代码来生成一个大小为 N(这里是 10)的数组不使用 ES6。 Cocco 的上述版本很接近,但不是最短的。
(function(n){for(a=[];n--;a[n]=n+1);return a})(10)
但是这个代码高尔夫(以最少的源代码字节解决特定问题的竞赛)的无可争议的赢家是 Niko Ruotsalainen 。使用数组构造器和 ES6 扩展运算符。 (大部分 ES6 语法都是有效的 typeScript,但以下不是。所以在使用时要谨慎)
[...Array(10).keys()]
a
。循环应该是 for(var a=[];n--;a[n]=n+1)
非常简单且容易准确地生成 1 - N
const [, ...结果] = Array(11).keys(); console.log('结果:',结果);
在 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
Array.from({length:N}, (v,i) => i+1)
使用来自 ES6 标准的新 Array 方法和 =>
函数语法(在撰写本文时仅限 Firefox)。
通过用 undefined
填充孔:
Array(N).fill().map((_, i) => i + 1);
Array.from
将“洞”变成 undefined
,因此 Array.map
可以按预期工作:
Array.from(Array(5)).map((_, i) => i + 1)
Array.from({length: N}, (v, k) => k)
。
Array.prototype.map.call
这样的冗长方法,例如对于从 document.querySelectorAll
返回的 NodeLists。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Array.from
将稀疏值变成未定义的。而是 Array(5)
被称为参数对象,该对象又将稀疏值解释为未定义值:)
快速地
这个解决方案可能是最快的,它的灵感来自 lodash _.range 函数(但我的更简单更快)
令 N=10, i=0, a=Array(N);而(i
基于
内存由 a=Array(N) 在开始时分配一次
使用增加索引 i++ - 看起来比减少索引 i 快大约 30% - (可能是因为 CPU 高速缓存在前向更快)
在 this answer 中使用 20 多种其他解决方案进行了速度测试
while/for
的当前(2020.12.11)现有答案的性能优势
在 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"))
Array(...Array(9)).map((_, i) => i); console.log(Array(...Array(9)).map((_, i) => i))
[...Array(9)].map((_, i) => i)
for(var i,a=[i=0];i<10;a[i++]=i);
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
似乎目前不在这个相当完整的答案列表中的唯一风味是具有生成器的风味。所以要解决这个问题:
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})()]
Array(8).fill(0).map(Number.call, Number)
窃取伊戈尔 Number.call
技巧,但使用 fill()
稍微缩短。仅适用于 ES6 及更高版本。
Array(5).fill().map((_, i) => i+1)
您可以使用 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]
我更喜欢这个,因为我发现它简单明了而且更容易。
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)