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

IT技术 javascript arrays
2021-01-13 06:58:37

我正在寻找以下任何替代方案,以创建包含 1 到 N 的 JavaScript 数组,其中 N 仅在运行时已知。

var foo = [];

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

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

6个回答

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

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

使用扩展运算符的较短版本

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

从 1 开始,将 map 函数传递给 Array from(),并带有一个具有length属性的对象

Array.from({length: 10}, (_, i) => i + 1)
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
请注意,这将始终从 0 开始。需要将 a 链接map到数组以调整值 ( [...Array(10).keys()].map(x => x++);) 以从 1 开始
2021-03-13 06:58:37
或者不使用keys并且只有 1 张地图 ->Array.from(Array(10)).map((e,i)=>i+1)
2021-03-15 06:58:37
或者不使用键和映射,只需将映射函数传递给 from Array.from(Array(10), (e,i)=>i+1)
2021-03-26 06:58:37
呃什么!?为什么map什么时候可以简单slice[...Array(N+1).keys()].slice(1)
2021-04-01 06:58:37
由于优先级增量发生在值返回之后,只需更改map(x => x++)map(x => ++x):)
2021-04-09 06:58:37

你可以这样做:

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.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;
}

从 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元素数组。区别在于,在前一个表达式中,每个元素都显式设置为 undefined,而在后者中,每个元素都从未设置过。根据以下文件.map()

callback仅对已分配值的数组索引调用;不会为已删除或从未分配值的索引调用它。

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

兼容性

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

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

多种方式使用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 和{ 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

展示所有表单的示例

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

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

甚至更简单

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

为了让 TS 编译器满意,请考虑用 lodash 替换未使用的参数: Array.from({ length: 5 }, (_, k) => k + 1);
2021-03-11 06:58:37
对从 0 开始的数组使用 k++
2021-03-29 06:58:37
当心 Array.from 在 IE 中不受支持,除非您对它进行 poly-filling。
2021-04-02 06:58:37
如果你想增加,不要使用k++,使用++k
2021-04-04 06:58:37
@bluejayke 我相信自从我发表评论以来,这个答案已经被编辑过,但我专门谈论的是Array.from({length: 5}, (v, k) => k+1);,它确实只迭代一次。
2021-04-05 06:58:37

如果我得到你想要的东西,你需要一个数字数组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/

你比我能更好地表达我的问题给你留下了深刻的印象,你确实是正确的,因为我需要的是一个数字数组,我以后可以循环遍历:)谢谢你的回答。
2021-04-01 06:58:37
我真的不明白为什么这个答案甚至有赞成票……尤其是当 OP 本人同意时,上面的一些评论没有任何意义,因为他本来可以这样做的var n = 45;
2021-04-02 06:58:37
@scunliffe:请注意,这new Array(45);不会“创建 45 个元素的数组”(含义相同[undefined,undefined,..undefined])。而是“创建长度为 45 的空数组” ( [undefined x 45]),与var foo = []; foo.length=45;. 这就是为什么forEach,并且map在这种情况下不适用。
2021-04-03 06:58:37
@Godders:如果这就是你要找的,你为什么需要一个数组?一个简单的var n = 45;然后循环1..n就可以了。
2021-04-05 06:58:37
@Godders - 请注意,如果您想在创建数组后将其减小到长度 M,只需使用foo.length = M--- The cut off info is lost。看到它在行动 ==> jsfiddle.net/ACMXp
2021-04-08 06:58:37

数组天生管理它们的长度。当它们被遍历时,它们的索引可以保存在内存中并在那时被引用。如果需要知道随机索引,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 中获取值,有几个选项:

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

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

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




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