【问题标题】:Tersest way to create an array of integers from 1..20 in JavaScript在 JavaScript 中从 1..20 创建整数数组的最简单方法
【发布时间】:2011-09-12 01:44:18
【问题描述】:

创建这个数组最简单的方法是什么:

var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
         11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

例如,for 循环:

var x = [];
for (var i=1;i<=20;i++) {
  x.push(i);
}

while 循环:

var x = [], i = 1, endInt = 20;
while (i <= endInt) {
  x.push(i);
  i++;
}

是否还有其他更简洁的示例 - 换句话说 - 更少的代码?我在想像在 Ruby 中的东西,我相信等效代码就像1..20 一样简单。我不知道 JavaScript 中的语法,但我想知道是否有更短的方法来做同样的事情。

更新:我没有考虑删除分号或var 以获得问题的答案,但我不得不承认这个问题暗示了这一点。我对算法比对字节更感兴趣。对不起,如果我不清楚!另外,把它变成一个函数也很简单,只需在它周围拍一下function range(start, end) { /* guts here */ } 就可以了。问题是“胆量”是否有新的方法。

【问题讨论】:

  • 代码简洁是否重要,或者这只是一个思想实验?
  • 真正的思想实验比什么都重要。我正在创建一个数组并实际上在考虑 PHP,我可以在其中执行 var $x = range(1, 20);... 就像,为什么不使用 JavaScript?
  • 为什么不在JS中创建函数range()并使用它呢?
  • push() 方法在这里实际上不是很聪明,因为动态数组增长。如果您事先知道字段的数量,您应该使用大小显式初始化并通过索引填充字段:x[i-start_i] = i;
  • 不禁认为 svicks 的评论是正确的答案。毕竟是JS。

标签: javascript algorithm


【解决方案1】:

最喜欢的方法

2015 年 9 月 13 日更新:

刚刚想出了这个适用于支持 ES6 标准的浏览器的新方法:

> Array(5).fill().map((x,i)=>i)
[0, 1, 2, 3, 4]

注意上面做了一点额外的工作(用undefined填充)但是相对于你可以通过使用for循环实现的加速来说相对较小,如果你忘记了.fill你可以很困惑为什么你的数组神秘地是[empty x 5]。您可以将上述内容封装为自定义函数,或者使用更有意的方法:

> Array.from(Array(5),(x,i)=>i)
[0, 1, 2, 3, 4]

你当然可以直接从那里进入你想做的任何事情,比如 python 的列表推导,例如[i**2 for i in range(5)]:

> Array.from(Array(5), (_,i)=> i**2)
[0, 1, 4, 9, 16]

...或者如果您想变得更复杂...:

> Array.from(Array(5), (_,i)=> {
    const R = /*some computation*/;
    return /*etc*/;
});

[2021 年 5 月编辑]:理论上,如今定义此类函数的最简单方法是 f=i=&gt;i?[...f(i-1),i]:[],您可以将 f 替换为 range1 或任何名称,但这会非常慢(二次复杂度),因为中间结构,所以永远不应该使用。 f=i=&gt;i?f(i-1)&amp;&amp;x.push(i)&amp;&amp;x:x=[] 是线性复杂性,但依赖于符号的滥用,不可读并且还污染全局变量。但是,由于现在定义箭头函数(不绑定而是继承 this)非常简洁,您可以包装上述解决方案:

const range1 = n=> Array.from(Array(n), (_,i)=> i+i);
// range1(5)==[1, 2, 3, 4, 5]

下面的一切都是历史:

经过一番思考,这是我能想到的 JavaScript 中标准 range(N) 函数的最短实现:

function range1(i){return i?range1(i-1).concat(i):[]}

注意:不要在生产中使用它;它是 O(N^2)

与当前投票最多的答案对比:

function range1(i){var x=[];var i=1;while(x.push(i++)<i){};return x}

例子:

> range1(5)
[1, 2, 3, 4, 5]

这就像递归的典型代表,虽然我预计它会更长,直到我想到三元 if 语句,它将它减少到 42 个必要的字符。

请注意,返回 [start,end) 的“标准”range 函数可以通过 .concat(i-1) 来编写。


更新:哦,我发现了一个非常短的版本,它通过滥用 for 循环、反向排序、赋值返回一个值的事实:for(y=[],i=20;y[--i]=i;){} 仅包含 25 个字符(尽管你会想要 var y您可以将其插入 for 循环,如果您不想要 0...19,则 +1)。如果你需要定义一个函数,它不会更短,如果你不需要创建一个函数,它比i?r(i-1).concat(i):[]短。


添加了一些性能分析测试用例:似乎除了标准的有序 for 循环之外的所有东西都慢了 10 倍,至少在 V8 上是这样。 https://jsperf.com/array-range-in-javascript (当然,如果你以函数式编程并且无论如何都会用函数调用来处理每个元素,那么这些都不重要。)

【讨论】:

  • 非常好!要设置范围 1-20:function range(i) {return i&gt;1 ? range(i-1).concat(i-1) : [];} 并使用 range(21) ;~)
  • 真聪明!如果我在哪里 OP 我会选择这个答案。
  • 哦,太棒了!非常巧妙地使用递归和concat()developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
  • 我应该提一下,虽然我的回答很简洁(如要求的那样),但它对于大范围可能效率不高,因为遗憾的是 javascript 的 .concat 可能不是 O(1) 操作。跨度>
  • 第一个 ES6 替代方案可能会抛出 Supplied parameters do not match any signature of call target. 错误。这是因为 Array 原型中的fill() 方法必须接收填充值。查看我的解决方案以使用 fill()method。
【解决方案2】:

它可以通过 ES6 的功能来完成,目前只有 Firefox 支持。我在这里找到了一个兼容性表:http://kangax.github.io/compat-table/es6/

Array.from(new Array(20), (x,i) => i+1)

如果你想有一些其他的范围,那么我想你可以这样做

Array.from(new Array(5), (x,i) => i+5)

然后是 [5,6,7,8,9]

【讨论】:

  • 这适用于 Chrome v45,如果您使用 Babel 转译 ES6,则可以使用。你也可以Array.from({ length: 20 }, (v, k) =&gt; k + 1);
【解决方案3】:

您可以使用 while 循环执行此操作,其中 push 发生在 condition.Array.push 返回数组的长度,这恰好与本例中的值相同。因此,您可以执行以下操作:

x = []; //normally would use var here
i = 1;  //normally would use var here
while(x.push(i++)<20){}

//at this point, x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

精简版(31 个字符)

x=[];i=1;while(x.push(i++)<20);

jsFiddle example

【讨论】:

  • 哦!我喜欢。虽然很反常。我的理解是.push() 返回数组的长度。在 Mozilla Docs 中:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… “push 方法可用于轻松地将值附加到数组。此方法的返回值是调用该方法的对象的新长度属性。”碰巧在以 1 开头的数组中,最后一个 push()ed 将是长度。哈!
  • @EndangeredMassa,x.Push() 返回新长度而不是值。
  • @EndangeredMassa。 x.push(i++) 是否等于 x 中元素的个数?
  • 啊,是的。在这种特定情况下,它们是相同的。
  • 他不使用var是为了节省空间,但是如果你实现了这个,请使用var,否则维护你的代码的人会找到你...
【解决方案4】:

while-- 是要走的路

var a=[],b=10;while(b--)a[b]=b+1

返回 [1,2,3,4,5,6,7,8,9,10]

用开始和长度解释

var array=[],length=20,start=5;while(length--)array[length]=length+start

返回 [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]

想要范围?

用开始和结束来解释

var array=[],end=30,start=25,a=end-start+1;while(a--)array[a]=end--

返回 [25, 26, 27, 28, 29, 30]

为--

for(var a=[],b=20;b>0;b--,a[b]=b+1)

对于++

for(var a=[],b=0;b<20;b++,a[b]=b+1)

为什么要走这条路?

  1. while -- 是最快的循环;

  2. 直接设置比push & concat快;

  3. [] 也比 new Array(10) 快;

  4. 它的代码并不比其他所有代码长多少

字节节省技术:

  1. 将参数用作函数变量的占位符
  2. 如果不需要,不要使用 new Array(),push(),concat()
  3. 仅在需要时放置“(){};”。
  4. 在短函数中使用 a,b,c,d...。

所以如果你想要这个功能

有开始,结束(范围)

function range(a,b,c,d){d=[];c=b-a+1;while(c--)d[c]=b--;return d}

所以现在 range(3,7) 返回 [3,4,5,6,7]

你在这里以多种方式保存字节,并且这个函数也非常快,因为它不使用concat,push,new Array并且它是​​用一段时间制作的--

【讨论】:

    【解决方案5】:

    如果你对 0-20 没问题,以下是我最近打高尔夫球时的最新最爱:

    [...'0'.repeat(21)].map((_,i)=>i)
    Array.from({length:21},(_,i)=>i)
    Array(21).fill().map((_,i)=>i)
    [...Array(21)].map((_,i)=>i)
    Array(21).map((_,i)=>i)
    [...Array(21).keys()]
    

    【讨论】:

      【解决方案6】:

      使用 ES6

      numArr = Array(5).fill(0).reduce(arr=&gt;{ arr.push(arr.length); return arr },[])

      【讨论】:

      • 短一点:Array( 5 ).fill().reduce( arr =&gt; ( arr.push( arr.length ), arr ), [] )
      【解决方案7】:

      我想不出字符少于 ~46 个的方法:

      var a=[];while(a.length&lt;20)a.push(a.length+1);

      当然,你可以用它来做一个函数。

      阅读有关函数的 cmets,您可以执行类似的操作

      var range = function (start, end) {
          var arr = [];
      
          while (start <= end) {
              arr.push(start++)
          }
      
          return arr;
      };
      

      然后range(1, 20) 将按预期返回数组。

      【讨论】:

      • 我不想复制 range() - 例如 Underscore.js 的方式:documentcloud.github.com/underscore/#range -- var x = _.range(1, 20); -- 问题更多的是关于底层方法和控制结构创建数组。我很好奇是否有我不知道的。
      • @artlung:不,你几乎得到了所有这些。循环或创建自己的方法,本质上是一个循环。
      【解决方案8】:

      我想这是最短的方法:

      var i=0, arr = [];
      while (i++<20){
        arr.push(i);
      }
      

      或关联EndangeredMassa 的答案中的“反常”代码:

      var i,arr; while (i=i||1, (arr=arr||[]).push(i++)<20){}
      

      【讨论】:

        【解决方案9】:

        你总是可以创建一个函数...

        function createNumArray(a, b) {
           var arr = [], 
               i = a;
        
            while((arr[arr.length] = i) < b) {i++}
            return arr;
        }
        

        这使您可以稍后编写简洁的代码,例如...

        var arr = createNumArray(1, 20);
        

        【讨论】:

          【解决方案10】:

          如果您希望在不考虑可读性的情况下无论如何都可以刮掉字符,这是我能做的最好的:

          var x=[],i=0
          while(i<20)
            x[i]=i+++1
          

          不过比你的好不了多少。

          编辑:

          实际上这样效果更好,并且减少了几个字符:

          var x=[],i=0
          while(i<20)
            x[i]=++i
          

          编辑 2:

          这是我用最少字符输入的一般“范围”函数的条目:

          function range(s,e){var x=[];while(s<e+1)x.push(s++);return x}
          

          同样,不要这样写代码。 :)

          【讨论】:

          • i+++1 应该做什么?你的分号在哪里?这是 JavaScript 吗?
          • 该构造使用++ 运算符,并在其中添加1 +1。不符合 Crockford 标准,但聪明而简洁。
          • 嘿,它运行并产生正确的结果。不,我不会这样写代码!分号是可选的(但我总是使用它们),并且 i+++1 与 (i++) + 1 相同
          • 你为什么要使用 i+++1 而不是 i+=2,这伤害了我的眼睛。
          • @Robert: i+=2 不是一回事,但在这种情况下你实际上可以使用 ++i 并且它可以工作。请注意,它在一般情况下不起作用,只是因为数组索引恰好比值小 1。
          【解决方案11】:

          如果您接受从 0 而不是 1 开始的计数器...

          const zeroNineteen = [...Array(20).keys()]; 
          // outputs [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
          

          如果你真的需要从 1 开始:

          const terserst = [...Array(21).keys()].slice(1);
          

          它有 30 个字符,但还是可读的,你不觉得吗?

          【讨论】:

            【解决方案12】:

            据我所知,您提到的使用 for 循环的选项是最简单的。

            也就是说,

            var x = [];
            for (var i=1;i<=20;i++) {
              x.push(i);
            }
            

            【讨论】:

              【解决方案13】:
              var i = 0;
              var x = [];
              while (i++ < 20) x.push(i);
              

              JSFiddle

              【讨论】:

              • 虽然这段代码 sn-p 可以解决问题,但代码外的including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
              【解决方案14】:

              我会扩展 Array 的原型以使其易于访问:

              Array.prototype.range = function(start, end) {
                  if (!this.length) {
                      while (end >= start) {
                          this.push(start++);
                      }
                  } else {
                      throw "You can only call 'range' on an empty array";
                  }
                  return this;
              };
              
              var array = [].range(1, 20);
              

              虽然就您正在寻找的语法糖而言,以上是我能想到的最接近的,但您可能想尝试CoffeeScript

              它支持你所追求的符号。

              CoffeeScript:

              test = [1..20]
              
              alert test
              

              呈现为 JavaScript:

              var test;
              test = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
              alert(test);
              

              您可以在他们的网站上试用实时示例,并在您输入时查看它所做的转换。

              只需点击顶部的 TRY COFFEESCRIPT 链接,您将获得一个控制台,您可以在其中测试一些代码。

              【讨论】:

              • 一切都很好,直到你的 js 需要与一些也喜欢扩展内置对象的第三方库合作......
              • 没有带来新的算法,但允许有趣和简洁的用法。我可以用那个。
              • @rob:如果一个人使用图书馆,他们应该确切地知道它的作用。我当然不会仅仅因为可能与库发生冲突就放弃扩展对象的做法。如果有冲突,您只需解决它。没什么大不了。至少它不应该是一个能胜任一半的程序员。
              • @artlung:是的,这是一个如此简单的过程,我不认为你会发现任何在算法上太令人兴奋的东西。我个人喜欢扩展原生类的原型(Object 除外)。这是该语言的一个很棒的功能,所以您不妨喜欢它。 :o)
              • @artlung:你检查过CoffeeScript吗?我不是很喜欢它,但有些人喜欢它。这都是关于语法糖的。而且它似乎支持that 1..20 type of range notation
              【解决方案15】:
              Array.from({length: n}).map((_, i) => i);
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多