Javascript 如何仅在 ES2015 中生成从 0 到 n 的数字范围?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36947847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 19:45:01  来源:igfitidea点击:

How to generate range of numbers from 0 to n in ES2015 only?

javascriptarraysecmascript-6

提问by Aditya Singh

I have always found the rangefunction missing from JavaScript as it is available in python and others? Is there any concise way to generate range of numbers in ES2015 ?

我总是发现rangeJavaScript 中缺少该函数,因为它在 python 和其他中可用?在 ES2015 中是否有任何简洁的方法来生成数字范围?

EDIT: MY question is different from the mentioned duplicate as it is specific to ES2015 and not ECMASCRIPT-5. Also I need the range to be starting from 0 and not specific starting number (though it would be good if that is there)

编辑:我的问题与提到的重复不同,因为它特定于 ES2015 而不是 ECMASCRIPT-5。此外,我需要范围从 0 开始,而不是特定的起始数字(尽管如果有它会很好)

回答by Delapouite

You can use the spread operator on the keys of a freshly created array.

您可以在新创建的数组的键上使用扩展运算符。

[...Array(n).keys()]

[...Array(n).keys()]

or

或者

Array.from(Array(n).keys())

Array.from(Array(n).keys())

The Array.from()syntax is necessary if working with TypeScript

Array.from()如果与打字稿工作语法是必要的

回答by Aditya Singh

I also found one more intuitive way using Array.from:

我还发现了一种更直观的使用方法Array.from

const range = n => Array.from({length: n}, (value, key) => key)

Now this rangefunction will return all the numbers starting from 0 to n-1

现在这个range函数将返回从 0 到 n-1 的所有数字

A modified version of the range to support startand endis:

的范围内的修改版本,以支持startend是:

const range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);

EDITAs suggested by @marco6, you can put this as a static method if it suits your use case

编辑正如@marco6 所建议的,如果它适合您的用例,您可以将其作为静态方法

Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);

and use it as

并将其用作

Array.range(3, 9)

回答by nkitku

With Delta

与达美

For javascript

对于 JavaScript

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((v, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

Array(10).fill().map((v, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]

[...Array(10)].map((v, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

const range = (from, to, step) =>
  Array(~~((to - from) / step) + 1) // '~~' is Alternative for Math.floor()
  .fill().map((v, i) => from + i * step);

range(0, 9, 2);
//=> [0, 2, 4, 6, 8]

Array.range = (from, to, step) => Array.from({
    length: ~~((to - from) / step) + 1
  },
  (v, k) => from + k * step
);

Array.range = (from, to, step) => [...Array(~~((to - from) / step) + 1)].map(
  (v, k) => from + k * 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

// Or
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

class Range2 {
  constructor(to = 0, step = 1, from = 0) {
    this[Symbol.iterator] = function*() {
      let i = 0,
        length = ~~((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]

// Or 
const Range2 = function*(to = 0, step = 1, from = 0) {
    let i = 0, length = ~~((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

For Typescript

对于打字稿

interface _Iterable extends Iterable < {} > {
  length: number;
}

class _Array < T > extends Array < T > {
  static range(from: number, to: number, step: number): number[] {
    return Array.from(
      ( < _Iterable > { length: Math.floor((to - from) / step) + 1 }),
      (v, k) => from + k * step
    );
  }
}
_Array.range(0, 9, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

Update

更新

class _Array<T> extends Array<T> {
    static range(from: number, to: number, step: number): number[] {
        return [...Array(~~((to - from) / step) + 1)].map(
            (v, k) => from + k * step
        );
    }
}
_Array.range(0, 9, 1);

Edit

编辑

class _Array<T> extends Array<T> {
    static range(from: number, to: number, step: number): number[] {
        return Array.from(Array(~~((to - from) / step) + 1)).map(
            (v, k) => from + k * step
        );
    }
}
_Array.range(0, 9, 1);

回答by Ben

For numbers 0 to 5

对于数字 0 到 5

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

回答by Getriax

So, in this case, it would be nice if Numberobject would behave like an Array object with the spread operator.

因此,在这种情况下,如果Number对象的行为类似于带有扩展运算符的 Array 对象,那就太好了。

For instance Arrayobject used with the spread operator:

例如与扩展运算符一起使用的Array对象:

let foo = [0,1,2,3];
console.log(...foo) // returns 0 1 2 3

It works like this because Array object has a built-in iterator.
In our case, we need a Numberobject to have a similar functionality:

它是这样工作的,因为 Array 对象有一个内置的迭代器。
在我们的例子中,我们需要一个Number对象来具有类似的功能:

[...3] //should return [0,1,2,3]

To do that we can simply create Number iterator for that purpose.

为此,我们可以简单地为此目的创建 Number 迭代器。

Number.prototype[Symbol.iterator] = function *() {
   for(let i = 0; i <= this; i++)
       yield i;
}

Now it is possible to create ranges from 0 to N with the spread operator.

现在可以使用扩展运算符创建从 0 到 N 的范围。

[...N] // now returns 0 ... N array

[...N] // 现在返回 0 ... N 数组

http://jsfiddle.net/01e4xdv5/4/

http://jsfiddle.net/01e4xdv5/4/

Cheers.

干杯。

回答by Iron Savior

A lot of these solutions build on instantiating real Array objects, which can get the job done for a lot of cases but can't support cases like range(Infinity). You could use a simple generator to avoid these problems and support infinite sequences:

许多这些解决方案建立在实例化真正的 Array 对象之上,这可以在很多情况下完成工作,但不能支持range(Infinity). 您可以使用一个简单的生成器来避免这些问题并支持无限序列:

function* range( start, end, step = 1 ){
  if( end === undefined ) [end, start] = [start, 0];
  for( let n = start; n < end; n += step ) yield n;
}

Examples:

例子:

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

i = range(10, Infinity);
i.next(); // { value: 10, done: false }
i.next(); // { value: 11, done: false }
i.next(); // { value: 12, done: false }
i.next(); // { value: 13, done: false }
i.next(); // { value: 14, done: false }

回答by user3500066

To support delta

支持增量

const range = (start, end, delta) => {
  return Array.from(
    {length: (end - start) / delta}, (v, k) => (k * delta) + start
  )
};

回答by user3500066

You can use a generator function, which creates the range lazily only when needed:

您可以使用生成器函数,它仅在需要时才懒惰地创建范围:

function* range(x, y) {
  while (true) {
    if (x <= y)
      yield x++;

    else
      return null;
  }
}

const infiniteRange = x =>
  range(x, Infinity);
  
console.log(
  Array.from(range(1, 10)) // [1,2,3,4,5,6,7,8,9,10]
);

console.log(
  infiniteRange(1000000).next()
);

You can use a higher order generator function to map over the rangegenerator:

您可以使用高阶生成器函数来映射range生成器:

function* range(x, y) {
  while (true) {
    if (x <= y)
      yield x++;

    else
      return null;
  }
}

const genMap = f => gx => function* (...args) {
  for (const x of gx(...args))
    yield f(x);
};

const dbl = n => n * 2;

console.log(
  Array.from(
    genMap(dbl) (range) (1, 10)) // [2,4,6,8,10,12,14,16,18,20]
);

If you are fearless you can even generalize the generator approach to address a much wider range (pun intended):

如果你无所畏惧,你甚至可以概括生成器方法来解决更广泛的问题(双关语):

const rangeBy = (p, f) => function* rangeBy(x) {
  while (true) {
    if (p(x)) {
      yield x;
      x = f(x);
    }

    else
      return null;
  }
};

const lte = y => x => x <= y;

const inc = n => n + 1;

const dbl = n => n * 2;

console.log(
  Array.from(rangeBy(lte(10), inc) (1)) // [1,2,3,4,5,6,7,8,9,10]
);

console.log(
  Array.from(rangeBy(lte(256), dbl) (2)) // [2,4,8,16,32,64,128,256]
);

Keep in mind that generators/iterators are inherently stateful that is, there is an implicit state change with each invocation of next. State is a mixed blessing.

请记住,生成器/迭代器本质上是有状态的,也就是说,每次调用next. 国家是喜忧参半。

回答by juanesarango

Range with step ES6, that works similar to python list(range(start, stop[, step])):

范围与步骤 ES6,其工作方式类似于 python list(range(start, stop[, step]))

const range = (start, stop, step = 1) => {
  return [...Array(stop - start).keys()]
    .filter(i => !(i % Math.round(step)))
    .map(v => start + v)
}

Examples:

例子:

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

回答by Zack

This function will return an integer sequence.

此函数将返回一个整数序列。

const integerRange = (start, end, n = start, arr = []) =>
  (n === end) ? [...arr, n]
    : integerRange(start, end, start < end ? n + 1 : n - 1, [...arr, n]);

$> integerRange(1, 1)
<- Array [ 1 ]

$> integerRange(1, 3)
<- Array(3) [ 1, 2, 3 ]

$> integerRange(3, -3)
<- Array(7) [ 3, 2, 1, 0, -1, -2, -3 ]