JavaScript函数类似Python范围()

时间:2011-11-25 18:33:20

标签: javascript python

JavaScript中的函数是否类似于Python的range()

我认为应该有一个更好的方法,而不是每次写下面的行:

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

26 个答案:

答案 0 :(得分:82)

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

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

答案 1 :(得分:70)

,没有,但你可以制作一个

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

请参阅this jsfiddle以获取证明。

JavaScript和Python中range()的比较

它的工作方式如下:

  • 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(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()类似的函数,您可以使用上述解决方案。

答案 2 :(得分:25)

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


除了已经说过的内容之外,Javascript 1.7+还提供对iterators and generators的支持,可用于创建range的惰性,内存效率版本,在Python2中类似于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

答案 3 :(得分:16)

Python range函数的端口由underscore.jslodash实用程序库(以及许多其他有用的工具)提供。从下划线文档复制的示例:

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

答案 4 :(得分:15)

@Tadeck@georg的答案融合在一起,我想出了这个:

function* range(start, stop, step = 1) {
    if (typeof stop === 'undefined') {
        // 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(0, 10, 2)) {
    console.log(i);
}
// Outputs => 0 2 4 6 8

答案 5 :(得分:12)

可以通过将迭代器附加到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

答案 6 :(得分:7)

你走了。

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

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

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

像这样使用:

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

答案 7 :(得分:5)

如果你需要指定范围的起始位置和结束位置,这里是其中一个答案的小扩展名:

.index

答案 8 :(得分:5)

以下是Python range()函数对JavaScript的自然适应性:

&#13;
&#13;
// 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]
&#13;
&#13;
&#13;

它支持任何可以与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回答相反,回复[]undefined或在step评估时返回无限循环0NaN,此生成器函数抛出类似于Python行为的异常。

答案 9 :(得分:4)

要获得大小为x的数组,这里是一个不使用任何库的单行

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

作为

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

答案 10 :(得分:3)

使用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
}

答案 11 :(得分:2)

您可以使用underscore库。它包含许多用于处理数组的有用函数。

答案 12 :(得分:1)

实际上,在 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));

答案 13 :(得分:1)

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

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

答案 14 :(得分:1)

  

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

这里所有的解决方案都指的是Python 2的范围(可能是由于您提供的代码示例)。但是在Python 3中,range()方法返回一个迭代器。 JavaScript还具有迭代器,并且迭代器比生成整个数组并将其存储在内存中更节省空间。

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

例如:

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

另一个示例(其他答案中已经介绍过)。将迭代器转换为数组(ES6):

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

答案 15 :(得分:0)

递归函数是实现此类功能的最佳解决方案。

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

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 不同的是,您必须提供两个或三个参数。

答案 16 :(得分:0)

function range(start, stop) {
    if (typeof stop == 'undefined') {
        stop = start;
        start = 0;
    }
   
    result = [...Array(stop).keys()].slice(start, stop);
    return result;
}

答案 17 :(得分:0)

NodeJ的一个选项是使用缓冲区:

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

很好的是,您可以直接在缓冲区上进行迭代:

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

您不能使用未初始化的数组来做到这一点:

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

但是,谁在他们的右脑中使用Buffer这样的目的;)

答案 18 :(得分:0)

  

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 ]

请注意,您不必使用in来遍历数组,而必须使用of。因此,i变量采用数组元素的值而不是索引。

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

答案 19 :(得分:0)

假设您需要一个简单的范围,只需一步即可:

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

请参阅here

答案 20 :(得分:0)

不,没有,但是你可以制造一个。

我偏爱range3的Python3行为。您将在下面的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.

答案 21 :(得分:0)

MDN建议采用这种方法:Sequence generator (range)

答案 22 :(得分:0)

pythonic使用JS'生成器(range)最好地模仿Python yield行为,同时支持range(stop)range(start, stop, step)用例。此外,pythonic的{​​{1}}函数会返回支持rangeGenerator的自定义构建的map对象,因此可以执行以下内容:

filter

使用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 中范围:

的代码
pythonic

答案 23 :(得分:0)

以下是范围

的另一个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}`)
}

答案 24 :(得分:0)

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

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

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

答案 25 :(得分:-1)

这是我的方法

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

输出

0
1
2
3
4