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

2020/09/18 03:31 · javascript ·  · 0评论

我正在寻找以下所有替代方案,以创建一个包含1到N的JavaScript数组,其中N仅在运行时才知道。

var foo = [];

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

在我看来,应该有一种没有循环的方法。

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

在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开始,将映射函数传递给Array 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)

结果:[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)中将无法使用

使用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 }黑客

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)

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

在上面的示例中,如果您真的想捕获1..N中的值,则可以代替注释和混乱,有两种选择:

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

    因此,如果您需要100个数字:

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

在ES6中,您可以执行以下操作:

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

http://jsbin.com/molabiluwa/edit?js,控制台

编辑:更改Array(45)为,Array(N)因为您已经更新了问题。

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

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

填写Arrayv8 的最快方法是:

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

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

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

[...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。

(基于最大整数值),还有更多关于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);

您可以使用此:

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]

使用ES2015 / ES6传播算子

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

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

如果您碰巧像我一样在您的应用程序中使用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]

查看本教程以获取更多信息。

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

最短的

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

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

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

创建从开始到结束(但不包括结束)的数字数组(正数和/或负数)。如果指定了负开始而没有结束或步长,则使用-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);
// ➜ []

填充的新方法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)

最终摘要报告.. Drrruummm Rolll-

这是不使用ES6生成大小为N(此处为10)的数组最短代码上面的Cocco的版本很接近,但不是最短的版本。

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

但是,这场Code Golf 无可争议的获胜者(竞争者以最少的源代码字节数解决了一个特定的问题)是Niko Ruotsalainen使用数组构造器和ES6传播算符(大多数ES6语法是有效的typeScript,但以下语法不是有效的。因此,在使用它时要谨慎)

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

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")

在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等尽管如此,正式地,这些类型化的数组仅在ES6中添加了)。例如:

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

ES5:

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

另外,在ES5中,对于map函数(如Array.from上述ES6中函数的第二个参数),可以使用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"))

使用=>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(...Array(9)).map((_, i) => i);

console.log(Array(...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})()]

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

我更喜欢这样做,因为我发现它简单直接。

只是另一个ES6版本。

通过使用Array.from第二个可选参数:

Array.from(arrayLike [,mapFn [,thisArg]])

我们可以从空Array(10)位置构建编号数组

Array.from(Array(10), (_, i) => i)

var arr = Array.from(Array(10), (_, i) => i);
document.write(arr);

使用不会修改生成函数的可迭代版本Number.prototype

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

console.log([...sequence(10)])
Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));

来源:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from

使用ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);

Object.keys(Array.apply(0, Array(3))).map(Number)

返回[0, 1, 2]Igor Shubin的出色回答非常相似,但欺骗性略低(一个字符更长)。

说明:

  • Array(3) // [undefined × 3]生成长度为n = 3的数组。不幸的是,这个数组对我们几乎没有用,所以我们必须…
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]使数组可迭代。注意:null最常见的是apply的第一个arg,但0则更短。
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] 然后获取数组的键(之所以起作用,是因为Arrays是typeof数组是具有键索引的对象。
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] 并映射到键,将字符串转换为数字。
本文地址:http://javascript.askforanswer.com/ruhechuangjianyigebaohan1ndeshuzu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!