JavaScript是否具有类似“ range()”的方法来在提供的范围内生成范围?


870

在PHP中,您可以...

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

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

为此,JavaScript是否内置任何内置功能?如果没有,我将如何实施?


1
Prototype.js具有$R功能,但除此之外,我并不这么认为。
易江2010年

这(相关的)问题有一些优秀的答案:stackoverflow.com/questions/6299500/...
BTK

Array.from("ABC") //['A', 'B', 'C']对于问题的第二部分,这是我能找到的最接近的东西。
Andrew_1510 '16

@ Andrew_1510您也可以split("")在此处使用
Alex

1
当情人的界限为零时,此衬砌:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Answers:


1495

号码

[...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和其他评论者)


71
因为如果在任何地方都有用,那么在JS中可能很有用。(JS可以执行函数式编程类型的东西,这可以受益于range(0语句。那和一千个其他原因,在某些半罕见的情况下可能有用)
Lodewijk

5
知道为什么简单地使用(new Array(5)).map(function (value, index) { return index; })不起作用吗?这将[undefined × 5]在Chrome DevTools中返回给我。
刘易斯

12
@Lewis因为用其定义的数组具有插槽,所以不会与map()它的一个朋友迭代。
Alex

65
Array.from(Array(5).keys())
nils petersohn16年

17
Array(5).fill()也是可映射的
nils petersohn

332

对于数字,您可以使用ES6 Array.from()它在当今除IE之外的所有情况下都适用

短版:

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

较长版本:

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

这将创建一个从0到19(含0)的数组。可以将其进一步简化为以下形式之一:

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


50
第一个示例甚至可以简化为[... Array(20).keys()]
Delapouite 2015年

27
比该Array.from()方法更简洁,并且比两者都更快:Array(20).fill().map((_, i) => i)
Stu Cox

2
@Delapouite太棒了!您应该单独回答,我会投票赞成!这也是此副本的完美答案。
三角帆

9
@Delapouite @jib以及:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh

1
@ icc97是的,linters可能会抱怨,尽管在JavaScript中省略了定义为与passing相同的函数参数undefined,所以fill()(不带参数)本身并不是错误的。该解决方案不使用填充值,因此,如果您愿意,可以使用fill(0)一些字符。
Stu Cox

121

我最喜欢的新表格(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)

5
let range =(start,stop,step = 1)=> Array(stop-start).fill(start).map((x,y)=> x + y * step)
rodfersou

4
@rodfersou仅供参考:您的示例是错误的。stop实际上不是停止/结束位置,而是计数/距离。(没有冒犯性,只是为了让人们意识到错字)
F Lekschas

4
对于困惑-由于Rodfersou在F Lekschas评论后进行了编辑,他的代码现在是正确的。
eedrah

1
您传入的参数最后Array(Math.ceil((stop - start) / step) + 1)需要+1,以真正模仿php的“包容”行为。
Johan Dettmar '18

3
这是实际上回答完全实现range方法的Javascript函数的全部问题的最高答案。当前在此之上的所有其他命令(lodash除外_.range)都实现基本迭代器,而不是具有启动,停止和步进的实际范围函数
icc97

99

这是我的2美分:

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

1
出色地使用了高阶函数。
Farzad YZ

5
这实际上是错误的,因为问题是要求提供开始和结束值。没有开始和计数/距离。
詹姆斯·罗比

73

它适用于字符和数字,通过可选步骤前进或后退。

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


53

简单范围功能:

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

为了合并BitInt数据类型,可以包括一些检查,以确保所有变量都相同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;
}

要删除高于stopeg 定义的值,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;
}

3
加上UNO的可用性和可读性。我看了很长时间的最佳代码段。
monsto

1
当需要考虑条件时step != 1,这不起作用。我的更新版本具有默认值:函数范围(开始,停止,步进){step = step || 1 var a = [开始],b =开始; while(((b + step)<stop){console.log(“ b:” + b +“。a:” + a +“。”); b + = step; a.push(b); } return a; }whilestepstep
daveharris

@daveharris我在上面添加了默认步骤(step || 1)
Polywhirl先生18年

36
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方法。
connectyourcharger

此方法仅适用于整数和字符。如果参数为null,未定义大,NaN,布尔值,数组,对象等,该方法返回以下错误:undefined method toUpperCase to etc
维克多

```if(typeof from!=='number'&& typeof from!=='string'){抛出新的TypeError('第一个参数应该是数字或字符')}} if(typeof from!==' number'&& typeof to!=='string'){抛出新的TypeError('第一个参数应该是数字或字符')}
Victor

36

好的,在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"]

2
我认为这些功能存在一对一的错误。应该是Array(end - start + 1)Array(end.charCodeAt(0) - start.charCodeAt(0) + 1)
Earcanal

24

方便的功能可以解决问题,请运行下面的代码段

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)以使其更简单(两个方向/步长的差异*偏移)
  • 得到长度后,我们在这里使用check创建一个带有初始化值的空数组new Array(length).fill(0);
  • 现在,我们有了一个[0,0,0,..]所需长度的数组。我们在其上进行映射,并使用返回所需值的新数组Array.map(function() {})
  • var direction = start < end ? 1 : 0;显然,如果start不小于,end我们需要向后移动。我的意思是从0转到5,反之亦然
  • 在每次迭代中,startingPoint+ stepSize* index将为我们提供所需的值

8
方便,最肯定的是。简单?我不敢苟同; 不管您将它做成一根衬垫。来自Python,这令人震惊。
PascalVKooten

@PascalvKooten,是的,如果我有内置的类似python的方法,那当然很棒,但这是我能得到的最简单的方法。事实证明,它在我的项目中很方便。
azerafati

像这样发布一个痛苦而复杂的代码片段,尤其是作为一个单行代码,却没有解释它是如何工作的?一个好的 SO答案的可怜示例,无论它是否“有效”。
Madbreaks'Dec 21'16

1
@Madbreaks,是的,您是对的。我一直很天真地使其成为一个班轮。只是想给大家一个快速便捷的解决方案
azerafati

22
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);

@nikkwong,_只是映射回调中参数的名称。您知道,在某些语言中,您可以使用_作为名称来指出未使用该变量。
Klesun '16

不过,这里_没有通过传递参数range。为什么不?
Nikk wong

2
井井有条!虽然,请务必注意它不适用于任何IE或Opera。
拉斐尔·泽维尔

4
这个答案需要解释,因为它不太适合SO。
Madbreaks

@RafaelXavier将通过Array.fill()polyfill
mwag

18

使用和声传播算子和箭头函数:

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

例:

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

那是最好的答案!
亨利H.15年

1
虽然不是最快的。
mjwrazor

在这种情况下,下划线“ _”代表什么?
Oleh Berehovskyi

@OlehBerehovskyi表示您实际上没有使用意图的lambda函数参数。警告有关未使用变量的短毛绒应该忽略它。
Micah Zoltu

18

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

使用ES6生成器的另一个版本(请参阅Paolo Moretti出色的ES6生成器答案):

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

1
Just const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov

@lokhmakov是的,你是对的。谢谢!刚在我的答案中应用了您的代码。
屈曲英雄

15

对各种范围函数做了一些研究。 检出jsperf比较做这些功能的不同方法的。当然不是一个完美或详尽的清单,但应该有所帮助:)

获胜者是...

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

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

同样有趣的观察是这些数组函数的chrome比firefox快多少。Chrome至少快4到5倍


请注意,这与包含步长参数的范围函数进行了比较
binaryfunt

15

标准Javascript没有内置函数来生成范围。几个javascript框架增加了对此类功能的支持,或者正如其他人指出的那样,您可以随时自己滚动。

如果您想仔细检查,则权威资源是ECMA-262 Standard


虽然我敢肯定在2010年会有一个很好的答案,但这不应再被视为最佳方法。您不应该扩展内置类型,例如Prototype.js倾向于这样做
Dana Woodman

@DanaWoodman感谢您提出来-我更新了答案以删除对Prototype.js的引用,因为这在2018
Mike Dinescu

19
好吧,这根本没有帮助。
Pithikos

@Pithikos我看到这个问题自从最初被提出以来就已经被编辑,OP希望知道JS中是否有本机范围函数。
Mike Dinescu

13

您可以使用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可以用生成器实现:

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部分是此问题的正确答案。我建议删除其他答案涵盖的其他部分。
joews 2015年

如果在循环外部使用生成器,则有些奇怪:x = range(1,10); // {} x; // {} //看起来像是一个空映射WTF!?!x.next()。value; // OK 1; x [3] //未定义,仅使用实数数组
Anona112

@ Anona112可用于Array.from将生成器转换为数组实例并检查输出。
Paolo Moretti

10

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

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

4
简短!=简单,但越简单越好。这是一个易于阅读的版本:const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]使用ES6语法
nafg

1
@nafg :const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];。也请对整个答案提出意见。
7vujy0f0hy

10

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

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

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


9

我会这样编码:

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]

8

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

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

附带说明,我创建了一个Gist,在其中进行了getRange()各种“增强” 功能。特别是,我的目标是捕获在上面的准系统变体中可能未解决的极端情况。此外,我添加了对字母数字范围的支持。换句话说,使用两个提供的输入(例如'C'和)'K'getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
按此

您不需要new关键字
Soldeplata Saketos

8

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

特别说明


7

虽然这不是来自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红线。
mjwrazor

7

至于生成给定范围的数字数组,我使用以下方法:

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 = []在循环内进行设置可能无法满足您的需求。
Alex 2015年

@alex,谢谢。没错,我也忘记在循环的每一遍上都增加“ start”参数。现在已修复。
jhaskell

它仍然不会产生期望的输出,如果我想要5-10的范围,它将给我[5, 6, 7, 8, 9, 10, 11, 12, 13, 14],我希望只有该数组的前半部分。
Alex 2015年

@alex,再次感谢您,我没有考虑基于输入的长度限制。查看更新的版本。
jhaskell

6

和谐发电机组支持除了IE11所有的浏览器

var take = function (amount, generator) {
    var a = [];

    try {
        while (amount) {
            a.push(generator.next());
            amount -= 1;
        }
    } catch (e) {}

    return a;
};

var takeAll = function (gen) {
    var a = [],
        x;

    try {
        do {
            x = a.push(gen.next());
        } while (x);
    } catch (e) {}

    return a;
};

var range = (function (d) {
    var unlimited = (typeof d.to === "undefined");

    if (typeof d.from === "undefined") {
        d.from = 0;
    }

    if (typeof d.step === "undefined") {
        if (unlimited) {
            d.step = 1;
        }
    } else {
        if (typeof d.from !== "string") {
            if (d.from < d.to) {
                d.step = 1;
            } else {
                d.step = -1;
            }
        } else {
            if (d.from.charCodeAt(0) < d.to.charCodeAt(0)) {
                d.step = 1;
            } else {
                d.step = -1;
            }
        }
    }

    if (typeof d.from === "string") {
        for (let i = d.from.charCodeAt(0); (d.step > 0) ? (unlimited ? true : i <= d.to.charCodeAt(0)) : (i >= d.to.charCodeAt(0)); i += d.step) {
            yield String.fromCharCode(i);
        }
    } else {
        for (let i = d.from; (d.step > 0) ? (unlimited ? true : i <= d.to) : (i >= d.to); i += d.step) {
            yield i;
        }
    }
});

例子

采取

范例1。

take 只花尽可能多的力气

take(10, range( {from: 100, step: 5, to: 120} ) )

退货

[100, 105, 110, 115, 120]

示例2

to 不需要

take(10, range( {from: 100, step: 5} ) )

退货

[100, 105, 110, 115, 120, 125, 130, 135, 140, 145]

takeAll

范例3。

from 不需要

takeAll( range( {to: 5} ) )

退货

[0, 1, 2, 3, 4, 5]

示例4

takeAll( range( {to: 500, step: 100} ) )

退货

[0, 100, 200, 300, 400, 500]

示例5

takeAll( range( {from: 'z', to: 'a'} ) )

退货

["z", "y", "x", "w", "v", "u", "t", "s", "r", "q", "p", "o", "n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a"]


根据我的建议进行了编辑:)
Xotic750

+1。就@alex而言,在for子句中不进行三元运算(尤其是不嵌套)将提高此处的可读性。
贾斯汀·约翰逊

5

...更多范围,使用生成器功能。

function range(s, e, str){
  // create generator that handles numbers & strings.
  function *gen(s, e, str){
    while(s <= e){
      yield (!str) ? s : str[s]
      s++
    }
  }
  if (typeof s === 'string' && !str)
    str = 'abcdefghijklmnopqrstuvwxyz'
  const from = (!str) ? s : str.indexOf(s)
  const to = (!str) ? e : str.indexOf(e)
  // use the generator and return.
  return [...gen(from, to, str)]
}

// usage ...
console.log(range('l', 'w'))
//=> [ 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' ]

console.log(range(7, 12))
//=> [ 7, 8, 9, 10, 11, 12 ]

// first 'o' to first 't' of passed in string.
console.log(range('o', 't', "ssshhhooooouuut!!!!"))
// => [ 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 't' ]

// only lowercase args allowed here, but ...
console.log(range('m', 'v').map(v=>v.toUpperCase()))
//=> [ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V' ]

// => and decreasing range ...
console.log(range('m', 'v').map(v=>v.toUpperCase()).reverse())

// => ... and with a step
console.log(range('m', 'v')
          .map(v=>v.toUpperCase())
          .reverse()
          .reduce((acc, c, i) => (i % 2) ? acc.concat(c) : acc, []))

// ... etc, etc.

希望这是有用的。


5

我的代码推广同事提出了以下内容(ES6),包括:

(s,f)=>[...Array(f-s+1)].map((e,i)=>i+s)

非包容性:

(s,f)=>[...Array(f-s)].map((e,i)=>i+s)


4

d3还具有内置范围功能。参见https://github.com/mbostock/d3/wiki/Arrays#d3_range

d3.range([开始,]停止[,步骤])

生成一个包含算术级数的数组,类似于Python内置范围。此方法通常用于遍历一系列数字或整数值,例如数组中的索引。与Python版本不同,自变量不需要是整数,但是如果由于浮点精度而使结果更容易预测。如果省略step,则默认为1。

例:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

我不知道D3存在。不会使用它们的range方法,但将使用此包。
mjwrazor

非常感谢。我使用D3并一直在寻找本机JS方法,却不知道我D3已经提供了它。
塞萨尔

4

使用range([start,] stop [,step])签名完成ES6的实现:

function range(start, stop, step=1){
  if(!stop){stop=start;start=0;}
  return Array.from(new Array(int((stop-start)/step)), (x,i) => start+ i*step)
}

如果要自动负步进,请添加

if(stop<start)step=-Math.abs(step)

或更简而言之:

range=(b, e, step=1)=>{
  if(!e){e=b;b=0}
  return Array.from(new Array(int((e-b)/step)), (_,i) => b<e? b+i*step : b-i*step)
}

如果范围很大,请查看Paolo Moretti的发电机方法


替换!stoptypeof stop === 'undefined',然后替换intMath.floor,并添加检查if (start > stop && step > 0)(否则,range(-3, -10)抛出异常而不是做一些理智的事情(翻转step的符号或返回[]))。否则,很好!
艾哈迈德·法西

4

为此有一个npm模块(“ bereich”是德语中“ range”的意思)。它利用了现代JavaScript的迭代器,因此您可以通过多种方式使用它,例如:

console.log(...bereich(1, 10));
// => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

const numbers = Array.from(bereich(1, 10));
// => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

for (const number of bereich(1, 10)) {
  // ...
}

它还支持降序范围(通过简单地交换minmax),并且还支持以外的步骤1

免责声明:我是本模块的作者,因此请以一小撮盐回答我。


4

这一项也相反。

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 ]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.