类似于 Python range()的 JavaScript 函数

JavaScript 中有类似于 Python 的 range()的函数吗?

我认为应该有一个更好的方法,而不是每次都写下这样的句子:

array = new Array();
for (i = 0; i < specified_len; i++) {
array[i] = i;
}
98397 次浏览

没有强,没有,只有 你可以做一个

JavaScript 对 Python 的 range()的实现

尝试使用 模拟它在 Python 中的工作方式,我将创建类似于下面这样的函数:

function range(start, stop, step) {
if (typeof stop == 'undefined') {
// one param defined
stop = start;
start = 0;
}


if (typeof step == 'undefined') {
step = 1;
}


if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
return [];
}


var result = [];
for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
result.push(i);
}


return result;
};

有关证明,请参阅 这把小提琴

JavaScript 与 Python 中 range()的比较

它的工作方式如下:

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

以及它的 Python 对应物 效果完全一样(至少在上面提到的例子中是这样) :

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

因此,如果需要一个与 Python 的 range()类似的函数,可以使用上述解决方案。

给你。

这将使用索引号写入(或覆盖)每个索引的值。

Array.prototype.writeIndices = function( n ) {
for( var i = 0; i < (n || this.length); ++i ) this[i] = i;
return this;
};

如果不提供数字,它将使用 Array 的当前长度。

像这样使用它:

var array = [].writeIndices(10);  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

2018年: 这个答案不断得到更多的支持,所以这里有一个更新。下面的代码已经过时了,但幸运的是 ES6标准化生成器和 yield关键字,并且它们得到了跨平台的普遍支持。使用 yield的惰性 range()的示例可以在 给你中找到。


除了已经说过的内容,Javascript 1.7 + 还提供了对 迭代器和生成器的支持,这可以用来创建一个懒惰的、内存高效的 range版本,类似于 Python 2中的 xrange:

function range(low, high) {
return {
__iterator__: function() {
return {
next: function() {
if (low > high)
throw StopIteration;
return low++;
}
}
}
}
}


for (var i in range(3, 5))
console.log(i); // 3,4,5

你可以使用 下划线库,它包含了几十个有用的函数来处理数组等等。

来自 Python2的 range函数的端口由 下划线 js浪荡实用程序库(以及许多其他有用的工具)提供。从下划线文档复制的示例:

_.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);
=> []

@ Tadeck@ georg的答案融合在一起,我得出了这样的结论:

function* range(start, stop, step = 1) {
if (stop == null) {
// one param defined
stop = start;
start = 0;
}


for (let i = start; step > 0 ? i < stop : i > stop; i += step) {
yield i;
}
}

要在 for 循环中使用它,需要 ES6/JS1.7 for-of 循环:

for (let i of range(5)) {
console.log(i);
}
// Outputs => 0 1 2 3 4


for (let i of range(0, 10, 2)) {
console.log(i);
}
// Outputs => 0 2 4 6 8


for (let i of range(10, 0, -2)) {
console.log(i);
}
// Outputs => 10 8 6 4 2

使用 ES6默认参数进一步细化。

let range = function*(start = 0, stop, step = 1) {
let cur = (stop === undefined) ? 0 : start;
let max = (stop === undefined) ? start : stop;
for (let i = cur; step < 0 ? i > max : i < max; i += step)
yield i
}

为了获得大小为 x的数组,这里有一个不使用任何库的一行程序

var range = n => Array(n + 1).join(1).split('').map((x, i) => i)

作为

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

对于 ES6中一个非常简单的范围:

let range = n => Array.from(Array(n).keys())

BigOmega 的评论,这可以用 传播语法缩短:

let range = n => [...Array(n).keys()]

仍然没有相当于 range()的内置函数,但是使用最新版本 ES2015,您可以构建自己的实现。这是一个有限的版本。限制,因为它没有考虑到步骤参数。最小,最大。

const range = (min = null, max = null) =>
Array.from({length:max ? max - min : min}, (v,k) => max ? k + min : k)

这是通过能够从具有 length属性的任何对象构建数组的 Array.from方法实现的。因此,只传入带有 length属性的简单对象将创建一个 ArrayIterator,该 ArrayIterator 将生成 length数量的对象。

这里有一个小的扩展,用于在需要同时指定范围的起始和结束位置的情况下给出其中一个答案:

let range = (start, end) => Array.from(Array(end + 1).keys()).slice(start);

下面是 Python 的 范围()函数对 JavaScript 的自然改编:

// Generate range from start (inclusive) to stop (exclusive):
function* range(start, stop, step = 1) {
if (stop === undefined) [start, stop] = [0, start];
if (step > 0) while (start < stop) yield start, start += step;
else if (step < 0) while (start > stop) yield start, start += step;
else throw new RangeError('range() step argument invalid');
}


// Examples:
console.log([...range(3)]);       // [0, 1, 2]
console.log([...range(0, 3)]);    // [0, 1, 2]
console.log([...range(0, 3, -1)]);// []
console.log([...range(0, 0)]);    // []
console.log([...range(-3)]);      // []
console.log([...range(-3, 0)]);   // [-3, -2, -1]

它支持任何参数,可以比较 0stop,并可以增加的 step。当数字不超过 Number.MAX_SAFE_INTEGER时,它的行为与 Python 版本相同。

请注意下列情况:

[...range(0, 0, 0)];        // RangeError: range() step argument invalid
[...range(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER + 2)];  // []
[...range(Number.MAX_SAFE_INTEGER + 2, Number.MAX_SAFE_INTEGER + 3)];  // Infinite loop
[...range(0.7, 0.8, 0.1)];  // [0.7, 0.7999999999999999]
[...range('1', '11')];      // ['1']
[...range('2', '22')];      // Infinite loop

@ Tadeck’s@ Volv’s@ janka102’s不同,@ Tadeck’s@ Volv’s@ janka102’sstep的值为 0NaN时返回 []undefined或进入无限循环,这个生成器函数抛出一个类似 Python 行为的异常。

可以通过将迭代器附加到 Number原型来实现

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


[...5] // will result in [0,1,2,3,4,5]

选自 Kyle Simpson 的课程: 重新思考异步 JavaScript

下面是该范围的另一个 es6实现

// range :: (from, to, step?) -> [Number]
const range = (from, to, step = 1) => {
//swap values if necesery
[from, to] = from > to ? [to, from] : [from, to]
//create range array
return [...Array(Math.round((to - from) / step))]
.map((_, index) => {
const negative = from < 0 ? Math.abs(from) : 0
return index < negative ?
from + index * step  :
(index - negative + 1) * step
})
}


range(-20, 0, 5)
.forEach(val => console.log(val))


for(const val of range(5, 1)){
console.log(`value ${val}`)
}

pythonic 使用 JS 的生成器(yield)最好地模仿 Python range的行为,同时支持 range(stop)range(start, stop, step)用例。此外,pythonicrange函数返回一个类似于 Python 的 Iterator对象,该对象支持 mapfilter,因此可以使用如下一行代码:

import {range} from 'pythonic';
// ...
const results = range(5).map(wouldBeInvokedFiveTimes);
// `results` is now an array containing elements from
// 5 calls to wouldBeInvokedFiveTimes

使用 npm安装:

npm install --save pythonic

我是 Python 的作者和维护者

MDN 推荐这种方法: 序列发生器(范围)

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


// Generate numbers range 0..4
console.log("range(0, 4, 1):", range(0, 4, 1));
// [0, 1, 2, 3, 4]


// Generate numbers range 1..10 with step of 2
console.log("\nrange(1, 10, 2):", range(1, 10, 2));
// [1, 3, 5, 7, 9]


// Generate the alphabet using Array.from making use of it being ordered as a sequence
console.log("\nrange('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x))", range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x)));
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

不,没有,但你可以做一个。

我比较喜欢 Python 3的 range ()行为,你可以在下面找到 JavaScript 对 Python range ()的实现:

function* range(start=0, end=undefined, step=1) {
if(arguments.length === 1) {end = start, start = 0}
    

[...arguments].forEach(arg => {
if( typeof arg !== 'number') {throw new TypeError("Invalid argument")}
})
if(arguments.length === 0) {throw new TypeError("More arguments neede")}
        

if(start >= end) return
yield start
yield* range(start + step, end, step)
}
         

// Use Cases
console.log([...range(5)])


console.log([...range(2, 5)])


console.log([...range(2, 5, 2)])
console.log([...range(2,3)])
// You can, of course, iterate through the range instance.

假设你只需要一个简单的步骤:

let range = (start, end)=> {
if(start === end) return [start];
return [start, ...range(start + 1, end)];
}

别的

let range = (start, end, step)=> {
if(start === end) return [start];
return [start, ...range(start + step, end)];
}

详情请参阅 给你

JavaScript 中有类似于 Python range ()的函数吗?

这里的所有解决方案都涉及到 Python2的范围(可能是因为您给出的代码示例)。但是在 Python3中,range ()方法返回一个迭代器。JavaScript 也有迭代器,它们比生成整个数组并存储在内存中更加节省空间。

因此,更准确地表示 Python3的 range(n)函数是 Array(n).keys()

例如:

for (let i of Array(n).keys()) {
console.log(i) // 0, 1, 2, 3, ..., n
}

还有一个例子(已经在其他答案中讨论过了):

let ary = [...Array(n).keys()];
// ary = [0, 1, 2, 3, ..., n]

JavaScript 中有类似于 Python range ()的函数吗?

如前所述: 没有,没有。但是你可以自己做。 我相信这是 ES6的一个有趣的方法。它的工作原理非常类似于 Python 2.7 range(),但是更加动态。

function range(start, stop, step = 1)
{
// This will make the function behave as range(stop)
if(arguments.length === 1)
{
return [...Array(arguments[0]).keys()]
}


// Adjusts step to go towards the stop value
if((start > stop && !(step < 0)) ||
(start < stop && !(step > 0)))
{
step *= -1
}


let returnArray = []
// Checks if i is in the interval between start and stop no matter if stop
// is lower than start or vice-versa
for(let i = start; (i-start)*(i-stop) <= 0; i += step)
{
returnArray.push(i)
}
return returnArray
}

这个函数可以有三种不同的表现方式(就像 Python 的 range ()一样) :

  1. range(stop)
  2. range(start, stop)
  3. range(start, stop, step)

这些例子:

console.log(range(5))
console.log(range(-2, 2))
console.log(range(2, -2))
console.log(range(10, 20, 2))

将给出以下输出:

[ 0, 1, 2, 3, 4 ]
[ -2, -1, 0, 1, 2 ]
[ 2, 1, 0, -1, -2 ]
[ 10, 12, 14, 16, 18, 20 ]

请注意,您必须使用 of,而不是使用 in操作符(如 python)迭代数组。因此,i变量假定数组元素的值,而不是索引。

for(let i of range(5))
{
// do something with i...
}

这是我的首选方法,它允许您像 Python 那样指定一个或两个输入。

function range(start, end) {
return Array.from(Array(end||start).keys()).slice(!!end*start)
}

我是这么做的

let n = 5
[...Array(n).keys()].map(x=>{console.log(x)})

输出

0
1
2
3
4

NodeJs 的一个选项是使用 Buffer:

[...Buffer.alloc(5).keys()]
// [ 0, 1, 2, 3, 4 ]

不错的地方在于,您可以直接在缓冲区上进行迭代:

Buffer.alloc(5).forEach((_, index) => console.log(index))
// 0
// 1
// 2
// 3
// 4

你不能使用未初始化的 Array:

Array(5).forEach((_, index) => console.log(index))
// undefined

但是,谁在他们的正常头脑使用缓冲区这样的目的;)

function range(start, stop) {
if (typeof stop == 'undefined') {
stop = start;
start = 0;
}
   

result = [...Array(stop).keys()].slice(start, stop);
return result;
}

实际上,在 Python range ()中返回一个可迭代的对象,我们知道迭代器比数组(或 Python 中的列表)更有效地利用内存。 因此,如果我们想在 JavaScript 中实现具有精确功能的相同概念,我们可以使用迭代器对象:

class range {


constructor(start, stop, step = 1) {
//check for invalid input
if (stop !== undefined && typeof stop !== 'number'
|| typeof start !== 'number'
|| typeof step !== 'number') {
throw Error('invalid input for range function');
}


//check if second argument is provided
if (stop === undefined) {
stop = start;
start = 0;
}


//initialize the object properties
this.start = start;
this.stop = stop;
this.step = step;
}


//create the iterator object with Symbol.iterator
[Symbol.iterator]() {
return {
current: this.start,
last: this.stop,
step: this.step,
//implement the next() method of the iterator
next() {
if (this.step === 0) {
return { done: true };
} else if (this.step > 0 ? this.current < this.last : this.current > this.last) {
let value = this.current;
this.current += this.step;
return { done: false, value };
} else {
return { done: true };
}
}
};
};
}

例如:

for (const num of new range(1, 10, 2)) {
console.log(num);
}

我们也可以很容易地创建一个数组:

let arr = [...new range(10, -5, -1)];

或:

let arr = Array.from(new range(10));

递归函数 是实现类似这样的东西的最佳解决方案。

如果你只想得到从零开始的数字

function range(n) {
if (n > 0){
return [...range(n-1), n];
};
return [0];
};
console.log("range(5) => ", range(5));

比如说,

range(5) = [...range(4), 5]
= [...range(3), 4, 5]
= [...range(2), 3, 4, 5]
= [...range(1), 2, 3, 4, 5]
= [...range(0), 1, 2, 3, 4, 5] // range(0) = [0]
= [0, 1, 2, 3, 4, 5] //final answer

这个函数还可以扩展如下

function range(start, stop, step=1){
if( stop > start){
return [...range(start, stop-step), stop];
}
return [start];
}
console.log("range(2, 8, 2) => ", range(2, 8, 2));

但是请注意,与 python 不同,您必须提供两个或三个参数。

TypeScript 对 Python 的 range ()的实现

const range = (start: number, stop?: number, step: number = 1) => {
if (stop === undefined) {
[start, stop] = [0, start];
}
return Array.from({ length: Math.ceil((stop - start) / step) }, (_, i) => start + step * i);
};


console.log(range(4)); // [0, 1, 2, 3]
console.log(range(3, 6)); // [3, 4, 5]
console.log(range(0, 10, 2)); // [0, 2, 4, 6, 8]
console.log(range(10, 0, -1)); // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
console.log(range(8, 2, -2)); // [8, 6, 4]
console.log(range(8, 2)); // []
console.log(range(8, 2, 2)); // []
console.log(range(1, 5, -1)); // []
console.log(range(1, 5, -2)); // []
console.log(range(6, 1, -2)); // [6, 4, 2]
console.log(range(1, 6, 2)); // [1, 3, 5]
/**
* range generator
*
* @param {Integer} start - Optional. An integer specifying at which position to start. Default is 0
* @param {Integer} stop  - Required. An integer specifying at which position to stop. Excluded.
* @param {Integer} step  - Optional. An integer specifying the incrementation. Default is 1
*/


function* range (start, stop, step = 1) {


if (arguments.length === 1) { [start, stop] = [0, start]; }


if (![start, stop, step].every(Number.isInteger)) { throw new TypeError('range needs integer arguments'); }


if ((start - stop) * step >= 0) { return []; }


let check = start > stop ? (a, b) => a > b : (a, b) => a < b;
while (check(start, stop)) { yield start, start += step; }
}


console.log([...range(4)]);
console.log([...range(2, 4)]);
console.log([...range(1, 4, 2)]);
console.log([...range(-4, -1, 1)]);
console.log([...range(10, 4, -2)]);
console.log([...range(-1, -4, -1)]);

一个简单的方法在打字没有错误检查。上下包括。

const range = (start: number, end: number | null = null, step: number = 1): number[] =>
[...Array(end === null ? start : Math.abs(end - start)).keys()]
.filter((n: number): boolean => n % step === 0)
.map((n: number): number => (end === null ? n : end < start ? Math.max(start, end) - n : n + start));

在 Javascript ES6中也是如此

const range = (start, end = null, step = 1) =>
[...Array(end === null ? start : Math.abs(end - start)).keys()]
.filter((n) => n % step === 0)
.map((n) => (end === null ? n : end < start ? Math.max(start, end) - n : n + start));
const range = function*(start, stop, inclusive=false) {
let dx = Math.sign(stop - start);
if (inclusive) stop += dx;
for (let x = start; x !== stop; x += dx) yield x;
}


const arange = (start, stop, inclusive) => [...range(start, stop, inclusive)];

对于任何寻找现代解决方案的人来说 [...Array(n).keys()]

一点简洁,包容的 es6乐趣

var rng=(s,e=null,d=1)=>{
if(e==null)var[s,e]=[0,s]//missing e? s is e
if(s>e)d=d<0?d:-d//s,e backwards? might flip sign
return[...Array(((e-s)/d+1) << 0).keys()].map(x=>d*x+s)
}


rng(3) -> [0,1,2,3]
rng(0,2) -> [0,1,2]
rng(4,6) -> [4,5,6]
rng(3,9,3) -> [3,6,9]
rng(10,27,5) -> [10,15,20,25]
rng(7,null,2) -> [0,2,4,6]
rng(3,-2) -> [3,2,1,0,-1,-2]
rng(3,-2,-2) -> [3,1,-1]
rng(3,-2,2) -> [3,1,-1]
rng(42,42) -> [42]

(从 Array ()中删除有用/兼容的 +1。)