【问题标题】:Does JavaScript have a method like "range()" to generate a range within the supplied bounds?JavaScript 是否有类似 \"range()\" 的方法在提供的范围内生成范围?
【发布时间】:2022-08-02 10:49:21
【问题描述】:

在 PHP 中,您可以...

range(1, 3); // Array(1, 2, 3)
range(\"A\", \"C\"); // Array(\"A\", \"B\", \"C\")

也就是说,有一个函数可以让您通过传递上限和下限来获取一系列数字或字符。

是否有任何内置于 JavaScript 的本机功能?如果没有,我将如何实施?

  • Prototype.js 有$R 函数,但除此之外我真的不这么认为。
  • 这个(相关的)问题有一些很好的答案:stackoverflow.com/questions/6299500/…
  • Array.from(\"ABC\") //[\'A\', \'B\', \'C\']这是我能找到的最接近问题第二部分的内容。
  • 当下限为零时,这一衬里:Array.apply(null, { length: 10 }).map(eval.call, Number)
  • 不,但您可以使用以下方式定义函数:const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));(请参阅 MSDN 中的 \'Sequence generator (range)\'笔记:此函数仅在指定所有参数时才有效(即range(1,5,1) 生成数组[1,2,3,4,5],但range(1,5) 生成一个空数组)

标签: javascript arrays functional-programming


【解决方案1】:

数字

[...Array(5).keys()];
 => [0, 1, 2, 3, 4]

字符迭代

String.fromCharCode(...[...Array('D'.charCodeAt(0) - 'A'.charCodeAt(0) + 1).keys()].map(i => i + 'A'.charCodeAt(0)));
 => "ABCD"

迭代

for (const x of Array(5).keys()) {
  console.log(x, String.fromCharCode('A'.charCodeAt(0) + x));
}
 => 0,"A" 1,"B" 2,"C" 3,"D" 4,"E"

作为函数

function range(size, startAt = 0) {
    return [...Array(size).keys()].map(i => i + startAt);
}

function characterRange(startChar, endChar) {
    return String.fromCharCode(...range(endChar.charCodeAt(0) -
            startChar.charCodeAt(0), startChar.charCodeAt(0)))
}

作为类型化函数

function range(size:number, startAt:number = 0):ReadonlyArray<number> {
    return [...Array(size).keys()].map(i => i + startAt);
}

function characterRange(startChar:string, endChar:string):ReadonlyArray<string> {
    return String.fromCharCode(...range(endChar.charCodeAt(0) -
            startChar.charCodeAt(0), startChar.charCodeAt(0)))
}

lodash.js _.range() 函数

_.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]
String.fromCharCode(..._.range('A'.charCodeAt(0), 'D'.charCodeAt(0) + 1));
 => "ABCD"

没有库的旧非 es6 浏览器:

Array.apply(null, Array(5)).map(function (_, i) {return i;});
 => [0, 1, 2, 3, 4]

console.log([...Array(5).keys()]);

(ES6 归功于 nils petersohn 和其他评论者)

【讨论】:

  • 因为如果它在任何地方都有用,它可能在 JS 中很有用。 (JS 可以做函数式编程类型的东西,这可以从 range(0 语句中受益。这和其他一千个原因在某些半罕见的情况下可能有用)
  • 知道为什么简单地使用(new Array(5)).map(function (value, index) { return index; }) 不起作用吗?这会在 Chrome DevTools 中为我返回 [undefined × 5]
  • @Lewis 因为用它定义的数组有空的不会被map() 或其朋友之一迭代的槽。
  • Array.from(Array(5).keys())
  • Array(5).fill() 也是可映射的
【解决方案2】:

对于数字,您可以使用 ES6 Array.from()which works in everything these days,IE 除外:

较短的版本:

Array.from({length: 20}, (x, i) => i);

更长的版本:

Array.from(new Array(20), (x, i) => i);​​​​​​

它创建了一个从 0 到 19 的数组。这可以进一步缩短为以下形式之一:

Array.from(Array(20).keys());
// or
[...Array(20).keys()];

也可以指定下限和上限,例如:

Array.from(new Array(20), (x, i) => i + *lowerBound*);

一篇文章更详细地描述了这一点:http://www.2ality.com/2014/05/es6-array-methods.html

【讨论】:

  • 第一个示例甚至可以简化为 [...Array(20).keys()]
  • Array.from() 方法更简洁,并且比两者都快:Array(20).fill().map((_, i) =&gt; i)
  • @Delapouite 太棒了!你应该把它作为一个单独的答案,我会投票给它!这也是this duplicate 的完美答案。
  • @Delapouite @jib 还有这个:Array.from({length: end - start}, (v, k) =&gt; k + start)
  • @icc97 是的,linters 可能会抱怨,尽管在 JavaScript 中省略了定义为与传递 undefined 相同的函数参数,所以 fill()(没有参数)不是错误的本身。该解决方案中不使用填充值,因此如果您愿意,可以使用fill(0) 来保存一些字符。
【解决方案3】:

我最喜欢的新表格(ES2015)

Array(10).fill(1).map((x, y) => x + y)

如果你需要一个带有step 参数的函数:

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)

MDN docs 建议的另一种可能的实现方式:

// Sequence generator function 
// (commonly referred to as "range", e.g. Clojure, PHP etc)
const range = (start, stop, step) => 
  Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step))

【讨论】:

  • 让 range = (start, stop, step=1) => Array(stop - start).fill(start).map((x, y) => x + y * step)
  • @rodfersou 仅供参考:你的例子是错误的。 stop 实际上不是停止/结束位置,而是计数/距离。 (无意冒犯,只是为了让人们意识到错字)
  • 对于困惑 - 由于在 F Lekschas 发表评论后 rodfersou 的编辑,他的代码现在是正确的。
  • 您传递给Array(Math.ceil((stop - start) / step) + 1) 的参数最后需要+1,才能真正模仿php 的“包容性”行为。
  • 这是实际上回答了完全实现 range 方法的 Javascript 函数的完整问题的最佳答案。目前在此之上的所有其他(除了 lodash 的_.range)都实现了基本的迭代器,而不是具有 start、stop 和 step 的实际范围函数
【解决方案4】:

这是我的 2 美分:

function range(start, end) {
  return Array.apply(0, Array(end - 1))
    .map((element, index) => index + start);
}

【讨论】:

  • 这实际上是错误的,因为问题是要求开始和结束值。不开始和计数/距离。
  • 这个答案没有按预期工作。输出不可用。
  • Array(end - 1) 更改为Array(end - start + 1) 时,它将按预期工作
【解决方案5】:

它适用于字符和数字,可以通过可选步骤向前或向后移动。

var range = function(start, end, step) {
    var range = [];
    var typeofStart = typeof start;
    var typeofEnd = typeof end;

    if (step === 0) {
        throw TypeError("Step cannot be zero.");
    }

    if (typeofStart == "undefined" || typeofEnd == "undefined") {
        throw TypeError("Must pass start and end arguments.");
    } else if (typeofStart != typeofEnd) {
        throw TypeError("Start and end arguments must be of same type.");
    }

    typeof step == "undefined" && (step = 1);

    if (end < start) {
        step = -step;
    }

    if (typeofStart == "number") {

        while (step > 0 ? end >= start : end <= start) {
            range.push(start);
            start += step;
        }

    } else if (typeofStart == "string") {

        if (start.length != 1 || end.length != 1) {
            throw TypeError("Only strings with one character are supported.");
        }

        start = start.charCodeAt(0);
        end = end.charCodeAt(0);

        while (step > 0 ? end >= start : end <= start) {
            range.push(String.fromCharCode(start));
            start += step;
        }

    } else {
        throw TypeError("Only string and number types are supported");
    }

    return range;

}

jsFiddle

如果增加本机类型是您的事,那么将其分配给Array.range

var range = function(start, end, step) {
    var range = [];
    var typeofStart = typeof start;
    var typeofEnd = typeof end;

    if (step === 0) {
        throw TypeError("Step cannot be zero.");
    }

    if (typeofStart == "undefined" || typeofEnd == "undefined") {
        throw TypeError("Must pass start and end arguments.");
    } else if (typeofStart != typeofEnd) {
        throw TypeError("Start and end arguments must be of same type.");
    }

    typeof step == "undefined" && (step = 1);

    if (end < start) {
        step = -step;
    }

    if (typeofStart == "number") {

        while (step > 0 ? end >= start : end <= start) {
            range.push(start);
            start += step;
        }

    } else if (typeofStart == "string") {

        if (start.length != 1 || end.length != 1) {
            throw TypeError("Only strings with one character are supported.");
        }

        start = start.charCodeAt(0);
        end = end.charCodeAt(0);

        while (step > 0 ? end >= start : end <= start) {
            range.push(String.fromCharCode(start));
            start += step;
        }

    } else {
        throw TypeError("Only string and number types are supported");
    }

    return range;

}

console.log(range("A", "Z", 1));
console.log(range("Z", "A", 1));
console.log(range("A", "Z", 3));


console.log(range(0, 25, 1));

console.log(range(0, 25, 5));
console.log(range(20, 5, 5));

【讨论】:

    【解决方案6】:

    简单范围函数:

    function range(start, stop, step) {
        var a = [start], b = start;
        while (b < stop) {
            a.push(b += step || 1);
        }
        return a;
    }
    

    要合并BigInt data type,可以包括一些检查,确保所有变量都相同typeof start

    function range(start, stop, step) {
        var a = [start], b = start;
        if (typeof start == 'bigint') {
            stop = BigInt(stop)
            step = step? BigInt(step): 1n;
        } else
            step = step || 1;
        while (b < stop) {
            a.push(b += step);
        }
        return a;
    }
    

    删除高于stop 定义的值,例如range(0,5,2) 将包括 6,这是不应该的。

    function range(start, stop, step) {
        var a = [start], b = start;
        while (b < stop) {
            a.push(b += step || 1);
        }
        return (b > stop) ? a.slice(0,-1) : a;
    }
    

    【讨论】:

    • 加上 UNO 的可用性和可读性。很久以来我见过的最好的代码 sn-p。
    • 这在step != 1 时不起作用,while 条件需要考虑step。我的更新版本具有默认 step 值:函数范围(开始,停止,步骤){ step = step || 1 var a=[开始],b=开始; while((b+step) < stop){ console.log("b: " + b + ".a: " + a + "."); b+=步; a.推(b); } 返回一个; }
    • @daveharris 我在上面添加了一个默认步骤,(step || 1)
    • 我不得不说,只要看一下,如果您尝试数百万条记录,它就会使您的计算机崩溃。如果没有,请尝试再添加一个零。我认为你不能超过一个超过 8 个零的数字。
    【解决方案7】:

    好的,在 JavaScript 中,我们没有像 range() 这样的函数PHP,所以我们需要创建一个非常简单的函数,我为您编写了几个单行函数并将它们分开数字字母表如下:

    为了数字

    function numberRange (start, end) {
      return new Array(end - start).fill().map((d, i) => i + start);
    }
    

    并称之为:

    numberRange(5, 10); //[5, 6, 7, 8, 9]
    

    为了字母表

    function alphabetRange (start, end) {
      return new Array(end.charCodeAt(0) - start.charCodeAt(0)).fill().map((d, i) => String.fromCharCode(i + start.charCodeAt(0)));
    }
    

    并称之为:

    alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]
    

    【讨论】:

    • 我认为这些函数中存在一个错误。应该是Array(end - start + 1)Array(end.charCodeAt(0) - start.charCodeAt(0) + 1)
    【解决方案8】:
    Array.range = function(a, b, step){
        var A = [];
        if(typeof a == 'number'){
            A[0] = a;
            step = step || 1;
            while(a+step <= b){
                A[A.length]= a+= step;
            }
        }
        else {
            var s = 'abcdefghijklmnopqrstuvwxyz';
            if(a === a.toUpperCase()){
                b = b.toUpperCase();
                s = s.toUpperCase();
            }
            s = s.substring(s.indexOf(a), s.indexOf(b)+ 1);
            A = s.split('');        
        }
        return A;
    }
        
        
    Array.range(0,10);
    // [0,1,2,3,4,5,6,7,8,9,10]
        
    Array.range(-100,100,20);
    // [-100,-80,-60,-40,-20,0,20,40,60,80,100]
        
    Array.range('A','F');
    // ['A','B','C','D','E','F')
        
    Array.range('m','r');
    // ['m','n','o','p','q','r']
    

    【讨论】:

    • 你真的不应该在Array 原型上使用 jerry-rig 方法。
    • 此方法仅适用于整数和字符。如果参数为null、undefined、NaN、boolean、array、object等,该方法返回如下错误:undefined method toUpperCase to etc!
    • 正如 miike3459 所写,如果有一天 Array.range 被添加到标准库中,您可能会遇到严重问题。
    【解决方案9】:

    https://stackoverflow.com/a/49577331/8784402

    使用 Delta/Step

    最小的单线
    [...Array(N)].map((_, i) => from + i * step);
    

    示例和其他替代方案

    [...Array(10)].map((_, i) => 4 + i * 2);
    //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
    
    Array.from(Array(10)).map((_, i) => 4 + i * 2);
    //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
    
    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((_, i) => 4 + i * 2);
    //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
    
    Array(10).fill().map((_, i) => 4 + i * -2);
    //=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
    
    范围函数
    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);
    

    https://stackoverflow.com/a/64599169/8784402

    使用单行生成字符列表

    const charList = (a,z,d=1)=>(a=a.charCodeAt(),z=z.charCodeAt(),[...Array(Math.floor((z-a)/d)+1)].map((_,i)=>String.fromCharCode(a+i*d)));
    
    console.log("from A to G", charList('A', 'G'));
    console.log("from A to Z with step/delta of 2", charList('A', 'Z', 2));
    console.log("reverse order from Z to P", charList('Z', 'P', -1));
    console.log("from 0 to 5", charList('0', '5', 1));
    console.log("from 9 to 5", charList('9', '5', -1));
    console.log("from 0 to 8 with step 2", charList('0', '8', 2));
    console.log("from α to ω", charList('α', 'ω'));
    console.log("Hindi characters from क to ह", charList('क', 'ह'));
    console.log("Russian characters from А to Я", charList('А', 'Я'));
    对于打字稿
    const charList = (p: string, q: string, d = 1) => {
      const a = p.charCodeAt(0),
        z = q.charCodeAt(0);
      return [...Array(Math.floor((z - a) / d) + 1)].map((_, i) =>
        String.fromCharCode(a + i * d)
      );
    };
    

    【讨论】:

    • 我想说的很全面
    • 全部 - 请阅读并投票。到目前为止,它应该是最佳答案。
    【解决方案10】:
    var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
    

    【讨论】:

    • 井井有条!虽然,重要的是要注意它不适用于任何 IE 或 Opera。
    • 这个答案需要解释,因为它不适合 SO。
    • @RafaelXavier 将在 IE 上使用 Array.fill() polyfill
    【解决方案11】:

    便利函数来解决这个问题,运行下面的代码 sn-p

    function range(start, end, step, offset) {
      
      var len = (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1;
      var direction = start < end ? 1 : -1;
      var startingPoint = start - (direction * (offset || 0));
      var stepSize = direction * (step || 1);
      
      return Array(len).fill(0).map(function(_, index) {
        return startingPoint + (stepSize * index);
      });
      
    }
    
    console.log('range(1, 5)=> ' + range(1, 5));
    console.log('range(5, 1)=> ' + range(5, 1));
    console.log('range(5, 5)=> ' + range(5, 5));
    console.log('range(-5, 5)=> ' + range(-5, 5));
    console.log('range(-10, 5, 5)=> ' + range(-10, 5, 5));
    console.log('range(1, 5, 1, 2)=> ' + range(1, 5, 1, 2));

    这是如何使用它

    范围(开始,结束,步长=1,偏移=0);

    • 包括-转发range(5,10) // [5, 6, 7, 8, 9, 10]
    • 包含-向后range(10,5) // [10, 9, 8, 7, 6, 5]
    • 一步 - 后退range(10,2,2) // [10, 8, 6, 4, 2]
    • 独家-转发range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
    • 偏移量-展开range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
    • 偏移-收缩range(5,10,0,-2) // [7, 8]
    • 步骤-展开range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

    希望你觉得它有用。


    这就是它的工作原理。

    基本上我首先计算结果数组的长度并创建一个填充为零的数组到该长度,然后用所需的值填充它

    • (step || 1) => 其他类似的方法是使用 step 的值,如果没有提供,请改用 1
    • 我们首先使用(Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1) 计算结果数组的长度以使其更简单(在两个方向/步长上的差异*偏移)
    • 得到长度后,我们使用new Array(length).fill(0);check here创建一个带有初始化值的空数组
    • 现在我们有一个数组[0,0,0,..] 到我们想要的长度。我们映射它并使用Array.map(function() {})返回一个包含我们需要的值的新数组
    • var direction = start &lt; end ? 1 : 0; 显然,如果start 不小于end,我们需要向后移动。我的意思是从 0 到 5,反之亦然
    • 在每次迭代中,startingPoint + stepSize * index 将为我们提供所需的值

    【讨论】:

    • 很方便,当然。简单的?我不敢苟同;不管你把它做成一个班轮。来自 Python,这令人震惊。
    • @PascalvKooten,是的,如果有像python这样的内置方法当然会很棒,但这是我能找到的最简单的方法。事实证明,它在我的项目中很方便。
    • 像这样发布一个令人痛苦的复杂代码 sn-p,尤其是作为单行代码并且没有解释它是如何工作的?一个糟糕的例子好的所以回答,无论它是否“有效”。
    • @Madbreaks,是的,你是对的。我一直天真地把它变成一个班轮。只是想给大家一个快速简单的解决方案
    【解决方案12】:

    --- 更新(感谢@lokhmakov 的简化)---

    另一个使用 ES6 生成器的版本(见伟大的Paolo Moretti answer with ES6 generators):

    const RANGE = (x,y) => Array.from((function*(){
      while (x <= y) yield x++;
    })());
    
    console.log(RANGE(3,7));  // [ 3, 4, 5, 6, 7 ]
    

    或者,如果我们只需要可迭代,那么:

    const RANGE_ITER = (x,y) => (function*(){
      while (x <= y) yield x++;
    })();
    
    for (let n of RANGE_ITER(3,7)){
      console.log(n);
    }
    
    // 3
    // 4
    // 5
    // 6
    // 7
    

    --- 原始代码是: ---

    const RANGE = (a,b) => Array.from((function*(x,y){
      while (x <= y) yield x++;
    })(a,b));
    

    const RANGE_ITER = (a,b) => (function*(x,y){
      while (x <= y) yield x++;
    })(a,b);
    

    【讨论】:

    • 只需const range = (x, y) =&gt; Array.from(function* () { while (x &lt;= y) yield x++; }())
    • @lokhmakov 是的,你是对的。谢谢你!刚刚在我的答案中应用了您的代码。
    • 这应该被视为优先考虑可迭代解决方案的答案。特别是对于大范围,这种方法更快并且节省空间。
    【解决方案13】:

    使用 Harmony spread operator 和箭头函数:

    var range = (start, end) => [...Array(end - start + 1)].map((_, i) => start + i);
    

    例子:

    range(10, 15);
    [ 10, 11, 12, 13, 14, 15 ]
    

    【讨论】:

    • 这是最好的答案!
    • 虽然不是最快的。
    【解决方案14】:

    对一些不同的范围函数做了一些研究。Checkout the jsperf comparison执行这些功能的不同方法。当然不是一个完美或详尽的清单,但应该有所帮助:)

    获胜者是...

    function range(lowEnd,highEnd){
        var arr = [],
        c = highEnd - lowEnd + 1;
        while ( c-- ) {
            arr[c] = highEnd--
        }
        return arr;
    }
    range(0,31);
    

    从技术上讲,它不是 Firefox 上最快的,但 chrome 上的疯狂速度差异(恕我直言)弥补了这一点。

    另一个有趣的观察是使用这些数组函数的 chrome 比 firefox 快多少。Chrome 至少快 4 到 5 倍.

    【讨论】:

    • 请注意,这是与包含步长参数的范围函数进行比较的
    【解决方案15】:

    您可以使用lodashUndescore.js range

    var range = require('lodash/range')
    range(10)
    // -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
    

    或者,如果您只需要一个连续的整数范围,您可以执行以下操作:

    Array.apply(undefined, { length: 10 }).map(Number.call, Number)
    // -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
    

    在 ES6 中range 可以用generators 实现:

    function* range(start=0, end=null, step=1) {
      if (end == null) {
        end = start;
        start = 0;
      }
    
      for (let i=start; i < end; i+=step) {
        yield i;
      }
    }
    

    此实现在迭代大型序列时节省了内存,因为它不必将所有值具体化到数组中:

    for (let i of range(1, oneZillion)) {
      console.log(i);
    }
    

    【讨论】:

    • ES6 部分现在是这个问题的正确答案。我建议删除其他答案涵盖的其他部分。
    • 如果在循环之外使用生成器会有些奇怪:x=range(1, 10);//{} x;//{}// 看起来像一个空地图 WTF!?! x.next().value;// OK 1 ;x[3] // 未定义,只有实数数组
    • @Anona112 您可以使用 Array.from 将生成器转换为数组实例并检查输出。
    【解决方案16】:

    range(start,end,step): 使用 ES6 迭代器

    你只要求一个上限和下限。在这里,我们也创建了一个步骤。

    您可以轻松地创建可以用作迭代器的range() 生成器函数。这意味着您不必预先生成整个数组。

    function * range ( start, end, step = 1 ) {
      let state = start;
      while ( state < end ) {
        yield state;
        state += step;
      }
      return;
    };
    

    现在您可能想要创建一些东西,从迭代器预生成数组并返回一个列表。这对于接受数组的函数很有用。为此我们可以使用Array.from()

    const generate_array = (start,end,step) =>
      Array.from( range(start,end,step) );
    

    现在您可以轻松生成静态数组,

    const array1 = generate_array(1,10,2);
    const array1 = generate_array(1,7);
    

    但是当某些东西需要一个迭代器(或者让你选择使用一个迭代器)时,你也可以轻松地创建一个。

    for ( const i of range(1, Number.MAX_SAFE_INTEGER, 7) ) {
      console.log(i)
    }
    

    特别说明

    【讨论】:

      【解决方案17】:

      这可能不是最好的方法。但是,如果您希望在一行代码中获得一系列数字。例如 10 - 50

      Array(40).fill(undefined).map((n, i) => i + 10)
      

      其中 40 是(结束 - 开始),10 是开始。这应该返回[10, 11, ..., 50]

      【讨论】:

        【解决方案18】:

        尚未实施!

        使用新的Number.rangeproposal(第 1 阶段):

        [...Number.range(1, 10)]
        //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        

        【讨论】:

          【解决方案19】:

          我会编写这样的代码:

          function range(start, end) {
              return Array(end-start).join(0).split(0).map(function(val, id) {return id+start});
          }  
          
          range(-4,2);
          // [-4,-3,-2,-1,0,1]
          
          range(3,9);
          // [3,4,5,6,7,8]
          

          它的行为类似于 Python 范围:

          >>> range(-4,2)
          [-4, -3, -2, -1, 0, 1]
          

          【讨论】:

            【解决方案20】:

            我个人最喜欢的:

            const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);
            

            【讨论】:

            • 也许更好[...Array(end-start+1)].map((el, ind) =&gt; ind + start);
            【解决方案21】:

            如果在 Visual Studio Code 上遇到错误:

            类型“IterableIterator”不是数组类型或字符串类型。使用编译器选项“--downlevelIteration”来允许迭代器的迭代。

            代替

            [...Array(3).keys()]
            

            你可以依靠

            Array.from(Array(3).keys())
            

            更多关于downlevelIteration

            【讨论】:

              【解决方案22】:

              一个有趣的挑战是编写最短的功能来做到这一点。递归救援!

              function r(a,b){return a>b?[]:[a].concat(r(++a,b))}
              

              在大范围内往往很慢,但幸运的是量子计算机指日可待。

              一个额外的好处是它是模糊的。因为我们都知道隐藏我们的代码不被窥探是多么重要。

              要真正彻底地混淆该功能,请执行以下操作:

              function r(a,b){return (a<b?[a,b].concat(r(++a,--b)):a>b?[]:[a]).sort(function(a,b){return a-b})}
              

              【讨论】:

              • Short != 简单,但越简单越好。这是一个更易于阅读的版本:const range = (a, b) =&gt; (a&gt;=b) ? [] : [a, ...range(a+1, b)],使用 ES6 语法
              • @nafg:const range = (a, b, Δ = 1) =&gt; (a &gt; b) ? [] : [a, ...range(a + Δ, b, Δ)];。还支持评论的整个答案。
              【解决方案23】:

              ES6

              使用 Array.from(文档here):

              const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
              

              【讨论】:

                【解决方案24】:
                (from, to) => [...Array(to - from)].map((_,i)=> i + from)
                

                【讨论】:

                  【解决方案25】:

                  可以如下创建一个大量使用 ES6 的相当简约的实现,特别注意 Array.from() 静态方法:

                  const getRange = (start, stop) => Array.from(
                    new Array((stop - start) + 1),
                    (_, i) => i + start
                  );
                  

                  【讨论】:

                  • 作为旁注,我创建了一个 Gist,其中我创建了一个“增强的”getRange() 功能。特别是,我的目标是捕捉上面的准系统变体中可能未解决的边缘情况。此外,我添加了对字母数字范围的支持。换句话说,使用两个提供的输入(如'C''K'(按此顺序))调用它会返回一个数组,其值是从字母“C”(含)到字母“K”的连续字符集(独家):getRange('C', 'K'); // =&gt; ["C", "D", "E", "F", "G", "H", "I", "J"]
                  • 您不需要 new 关键字
                  【解决方案26】:

                  标准 Javascript 没有生成范围的内置函数。一些 javascript 框架添加了对此类功能的支持,或者正如其他人指出的那样,您始终可以自己开发。

                  如果您想仔细检查,确定的资源是ECMA-262 Standard

                  【讨论】:

                  • 虽然我确信 2010 年的答案非常好,但这不应再被视为最佳方法。你不应该像 Prototype.js 那样扩展内置类型 ?
                  • @DanaWoodman 感谢您提出这个问题 - 我已经更新了答案以删除对 Prototype.js 的引用,因为它在 2018 年确实已经过时了
                  • 好吧,这根本没有帮助。
                  • @Pithikos我看到这个问题自最初被问起以来已经被编辑过,OP想知道JS中是否有本机范围函数。
                  【解决方案27】:

                  虽然这不是来自PHP, 但对range 的模仿来自Python.

                  function range(start, end) {
                      var total = [];
                  
                      if (!end) {
                          end = start;
                          start = 0;
                      }
                  
                      for (var i = start; i < end; i += 1) {
                          total.push(i);
                      }
                  
                      return total;
                  }
                  
                  console.log(range(10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
                  console.log(range(0, 10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                  console.log(range(5, 10)); // [5, 6, 7, 8, 9] 
                  

                  【讨论】:

                  • +1 最快。数组为 -36768 - 36768,耗时 3 毫秒,第二名是 13 毫秒,并且有 IDE 红线。
                  【解决方案28】:

                  这个也可以反过来。

                  const range = ( a , b ) => Array.from( new Array( b > a ? b - a : a - b ), ( x, i ) => b > a ? i + a : a - i );
                  
                  range( -3, 2 ); // [ -3, -2, -1, 0, 1 ]
                  range( 1, -4 ); // [ 1, 0, -1, -2, -3 ]
                  

                  【讨论】:

                    【解决方案29】:

                    至于为给定范围生成数值数组,我使用这个:

                    function range(start, stop)
                    {
                        var array = [];
                    
                        var length = stop - start; 
                    
                        for (var i = 0; i <= length; i++) { 
                            array[i] = start;
                            start++;
                        }
                    
                        return array;
                    }
                    
                    console.log(range(1, 7));  // [1,2,3,4,5,6,7]
                    console.log(range(5, 10)); // [5,6,7,8,9,10]
                    console.log(range(-2, 3)); // [-2,-1,0,1,2,3]
                    

                    显然,它不适用于字母数组。

                    【讨论】:

                    • 在循环内设置array = [] 可能无法满足您的需求。
                    • @亚历克斯,谢谢。你是对的,我也忘了在循环的每次传递中增加“start”参数。现在已经修好了。
                    • 它仍然不会产生所需的输出,如果我想要范围 5-10,它会给我[5, 6, 7, 8, 9, 10, 11, 12, 13, 14],我只希望该数组的前半部分。
                    • @alex,再次感谢您,我没有考虑基于输入的长度限制。查看更新版本。
                    【解决方案30】:

                    用这个。它创建一个具有给定数量的值(未定义)的数组,在以下示例中有 100 个索引,但它不相关,因为这里您只需要键。它在数组 100 + 1 中使用,因为数组始终基于 0 索引。因此,如果要生成 100 个值,则索引从 0 开始;因此最后一个值总是 99 而不是 100。

                    range(2, 100);
                    
                    function range(start, end) {
                        console.log([...Array(end + 1).keys()].filter(value => end >= value && start <= value ));
                    }

                    【讨论】:

                      猜你喜欢
                      • 2017-09-09
                      • 1970-01-01
                      • 2020-09-29
                      • 1970-01-01
                      • 2011-05-31
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多