Javascript 如何创建一个包含 1...N 的数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3746725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create an array containing 1...N
提问by Godders
I'm looking for any alternatives to the below for creating a JavaScript array containing 1 through to N where N is only known at runtime.
我正在寻找以下任何替代方案,以创建包含 1 到 N 的 JavaScript 数组,其中 N 仅在运行时已知。
var foo = [];
for (var i = 1; i <= N; i++) {
foo.push(i);
}
To me it feels like there should be a way of doing this without the loop.
对我来说,感觉应该有一种没有循环的方法。
采纳答案by scunliffe
If I get what you are after, you want an array of numbers 1..n
that you can later loop through.
如果我得到你想要的东西,你需要一个数字数组1..n
,你可以稍后循环。
If this is all you need, can you do this instead?
如果这就是你所需要的,你可以这样做吗?
var foo = new Array(45); // create an empty array with length 45
then when you want to use it... (un-optimized, just for example)
那么当你想使用它时......(未优化,仅举个例子)
for(var i = 0; i < foo.length; i++){
document.write('Item: ' + (i + 1) + ' of ' + foo.length + '<br/>');
}
e.g. if you don't need to storeanything in the array, you just need a container of the right length that you can iterate over... this might be easier.
例如,如果你不需要在数组中存储任何东西,你只需要一个长度合适的容器,你可以迭代......这可能更容易。
See it in action here: http://jsfiddle.net/3kcvm/
在这里查看它的实际效果:http: //jsfiddle.net/3kcvm/
回答by Niko Ruotsalainen
回答by Igor Shubin
You can do so:
你可以这样做:
var N = 10;
Array.apply(null, {length: N}).map(Number.call, Number)
result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
or with random values:
或随机值:
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]
导致:[0.7082694901619107,0.9572225909214467,0.8586748542729765,0.8653848143294454,0.008339877473190427,0.9911756622605026,0.8133423360995948,0.8377588465809822,0.5577575915958732,0.16363654541783035]
Explanation
解释
First, note that Number.call(undefined, N)
is equivalent to Number(N)
, which just returns N
. We'll use that fact later.
首先,请注意它Number.call(undefined, N)
等价于Number(N)
,它只返回N
。我们稍后会用到这个事实。
Array.apply(null, [undefined, undefined, undefined])
is equivalent to Array(undefined, undefined, undefined)
, which produces a three-element array and assigns undefined
to each element.
Array.apply(null, [undefined, undefined, undefined])
等价于Array(undefined, undefined, undefined)
,它生成一个三元素数组并分配undefined
给每个元素。
How can you generalize that to Nelements? Consider how Array()
works, which goes something like this:
您如何将其推广到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)
also accepts a duck-typed array-like object as its second parameter. If we invoke Array.apply(null, { length: N })
, then it will execute
从 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;
}
Now we have an N-element array, with each element set to undefined
. When we call .map(callback, thisArg)
on it, each element will be set to the result of callback.call(thisArg, element, index, array)
. Therefore, [undefined, undefined, …, undefined].map(Number.call, Number)
would map each element to (Number.call).call(Number, undefined, index, array)
, which is the same as Number.call(undefined, index, array)
, which, as we observed earlier, evaluates to index
. That completes the array whose elements are the same as their index.
现在我们有一个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
。这完成了其元素与其索引相同的数组。
Why go through the trouble of Array.apply(null, {length: N})
instead of just Array(N)
? After all, both expressions would result an an N-element array of undefined elements. The difference is that in the former expression, each element is explicitly setto undefined, whereas in the latter, each element was never set. According to the documentation of .map()
:
为什么要经历麻烦Array.apply(null, {length: N})
而不是仅仅Array(N)
?毕竟,这两个表达式都会产生一个包含未定义元素的N元素数组。区别在于,在前一个表达式中,每个元素都显式设置为 undefined,而在后者中,每个元素都从未设置过。根据以下文件.map()
:
callback
is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
callback
仅对已分配值的数组索引调用;不会为已删除或从未分配值的索引调用它。
Therefore, Array(N)
is insufficient; Array(N).map(Number.call, Number)
would result in an uninitialized array of length N.
因此,Array(N)
是不够的;Array(N).map(Number.call, Number)
将导致长度为N的未初始化数组。
Compatibility
兼容性
Since this technique relies on behaviour of Function.prototype.apply()
specified in ECMAScript 5, it will not workin pre-ECMAScript 5 browsers such as Chrome 14 and Internet Explorer 9.
由于此技术依赖Function.prototype.apply()
于 ECMAScript 5中指定的行为,因此它不适用于 ECMAScript 5 之前的浏览器,例如 Chrome 14 和 Internet Explorer 9。
回答by Abdennour TOUMI
Multiple ways using ES6
多种方式使用ES6
Using spread operator (...
) and keys method
使用扩展运算符 ( ...
) 和键方法
[ ...Array(N).keys() ].map( i => i+1);
Fill/Map
填充/贴图
Array(N).fill().map((_, i) => i+1);
Array.from
数组.from
Array.from(Array(N), (_, i) => i+1)
Array.from and { length: N }
hack
Array.from 和{ length: N }
hack
Array.from({ length: N }, (_, i) => i+1)
Note about generalised form
关于广义形式的注意事项
All the forms above can produce arrays initialised to pretty much any desired values by changing i+1
to expression required (e.g. i*2
, -i
, 1+i*2
, i%2
and etc). If expression can be expressed by some function f
then the first form becomes simply
所有上述形式通过改变初始化为几乎任何期望的值可以产生阵列i+1
所需表达(例如i*2
,-i
,1+i*2
,i%2
和等等)。如果表达式可以用某个函数来表达,f
那么第一种形式就变得简单了
[ ...Array(N).keys() ].map(f)
Examples:
例子:
Array.from({length: 5}, (v, k) => k+1);
// [1,2,3,4,5]
Since the array is initialized with undefined
on each position, the value of v
will be undefined
由于数组是undefined
在每个位置上初始化的,因此 的值v
将是undefined
Example showcasing all the forms
展示所有表单的示例
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)
More generic example with custom initialiser function f
i.e.
带有自定义初始化函数的更通用示例,f
即
[ ...Array(N).keys() ].map((i) => f(i))
or even simpler
甚至更简单
[ ...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)
回答by vol7ron
Arrays innately manage their lengths. As they are traversed, their indexes can be held in memory and referenced at that point. If a random index needs to be known, the indexOf
method can be used.
数组天生管理它们的长度。当它们被遍历时,它们的索引可以保存在内存中并在那时被引用。如果需要知道随机索引,indexOf
可以使用该方法。
This said, for your needs you may just want to declare an array of a certain size:
这就是说,根据您的需要,您可能只想声明一个特定大小的数组:
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
ES6
Spread
传播
Making use of the spread operator (...
) and keys
method, enables you to create a temporary array of size N to produce the indexes, and then a new array that can be assigned to your variable:
利用扩展运算符 ( ...
) 和keys
方法,您可以创建一个大小为 N 的临时数组来生成索引,然后创建一个可以分配给变量的新数组:
var foo = [ ...Array(N).keys() ];
Fill/Map
填充/贴图
You can first create the size of the array you need, fill it with undefined and then create a new array using map
, which sets each element to the index.
您可以首先创建所需数组的大小,用 undefined 填充它,然后使用 来创建一个新数组map
,它将每个元素设置为索引。
var foo = Array(N).fill().map((v,i)=>i);
Array.from
数组.from
This should be initializing to length of size N and populating the array in one pass.
这应该初始化为大小为 N 的长度并一次性填充数组。
Array.from({ length: N }, (v, i) => i)
In lieu of the comments and confusion, if you really wanted to capture the values from 1..N in the above examples, there are a couple options:
代替评论和混淆,如果你真的想从上面的例子中捕获 1..N 的值,有几个选项:
- if the index is available, you can simply increment it by one (e.g.,
++i
). in cases where index is not used -- and possibly a more efficient way -- is to create your array but make N represent N+1, then shift off the front.
So if you desire 100 numbers:
let arr; (arr=[ ...Array(101).keys() ]).shift()
- 如果索引可用,您可以简单地将其加一(例如,
++i
)。 在不使用索引的情况下——并且可能是一种更有效的方法——是创建你的数组,但让 N 代表 N+1,然后从前面移开。
所以如果你想要 100 个数字:
let arr; (arr=[ ...Array(101).keys() ]).shift()
回答by Nate
In ES6 you can do:
在 ES6 中,您可以执行以下操作:
Array(N).fill().map((e,i)=>i+1);
Array(N).fill().map((e,i)=>i+1);
http://jsbin.com/molabiluwa/edit?js,console
http://jsbin.com/molabiluwa/edit?js,控制台
Edit:
Changed Array(45)
to Array(N)
since you've updated the question.
编辑:更改Array(45)
为Array(N)
因为您更新了问题。
console.log(
Array(45).fill(0).map((e,i)=>i+1)
);
回答by Evan
Use the very popular Underscore _.range method
使用非常流行的Underscore _.range 方法
// _.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); // => []
回答by Ian Henry
function range(start, end) {
var foo = [];
for (var i = start; i <= end; i++) {
foo.push(i);
}
return foo;
}
Then called by
然后被调用
var foo = range(1, 5);
There is no built-in way to do this in Javascript, but it's a perfectly valid utility function to create if you need to do it more than once.
在 Javascript 中没有内置的方法可以做到这一点,但是如果您需要多次创建它,它是一个非常有效的实用函数。
Edit: In my opinion, the following is a better range function. Maybe just because I'm biased by LINQ, but I think it's more useful in more cases. Your mileage may vary.
编辑:在我看来,以下是更好的范围函数。也许只是因为我对 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;
}
回答by аlex dyky?
the fastest way to fill an Array
in v8 is:
Array
在 v8 中填充 an 的最快方法是:
[...Array(5)].map((_,i) => i);
result will be: [0, 1, 2, 3, 4]
结果将是: [0, 1, 2, 3, 4]
回答by bluejayke
This question has a lot of complicated answers, but a simple one-liner:
这个问题有很多复杂的答案,但一个简单的单行:
[...Array(255).keys()].map(x => x + 1)
Also, although the above is short (and neat) to write, I think the following is a bit faster (for a max length of:
另外,虽然上面写的很短(而且很整洁),但我认为下面的要快一些(最大长度为:
127, Int8,
127, Int8,
255, Uint8,
第255话
32,767, Int16,
32,767, Int16,
65,535, Uint16,
65,535, Uint16,
2,147,483,647, Int32,
2,147,483,647, Int32,
4,294,967,295, Uint32.
4,294,967,295,Uint32。
(based on the max integer values), also here's more on Typed Arrays):
(基于最大整数值),这里还有更多关于Typed Arrays):
(new Uint8Array(255)).map(($,i) => i + 1);
Although this solution is also not so ideal, because it creates two arrays, and uses the extra variable declaration "$" (not sure any way to get around that using this method). I think the following solution is the absolute fastest possible way to do this:
虽然这个解决方案也不是那么理想,因为它创建了两个数组,并使用了额外的变量声明“$”(不确定使用这种方法有什么方法可以解决这个问题)。我认为以下解决方案是绝对最快的方法:
for(var i = 0, arr = new Uint8Array(255); i < arr.length; i++) arr[i] = i + 1;
Anytime after this statement is made, you can simple use the variable "arr" in the current scope;
执行此语句后的任何时候,您都可以简单地使用当前作用域中的变量“arr”;
If you want to make a simple function out of it (with some basic verification):
如果你想用它做一个简单的功能(有一些基本的验证):
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
);
so, with the above function, the above super-slow "simple one-liner" becomes the super-fast, even-shorter:
所以,有了上面的功能,上面的超慢“简单单行”变成了超快,甚至更短:
range(1,14000);