Функция JavaScript, похожая на диапазон Python()


есть ли функция в JavaScript, похожая на Python range()?

Я думаю, что там должен быть лучший способ, чем писать следующие строки каждый раз:

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

15 ответов:

нет, нет, но вы можете сделать один.

реализация 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;
};

посмотреть этот jsfiddle для доказательства.

сравнение между range() в JavaScript и 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(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(), вы можете использовать вышеуказанные решения.

для очень простого диапазона в ES6:

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

2018: этот ответ продолжает получать upvotes, так что вот обновление. Приведенный ниже код устарел, но, к счастью, ES6 стандартизированные генераторы и yield ключевое слово, и они повсеместно поддерживаются на разных платформах. Пример ленивого range() используя yield можно найти здесь.


В дополнение к тому, что уже сказано, Javascript 1.7+ обеспечивает поддержку итераторы и генераторы который может быть использован для создания ленивого, эффективной памяти версия range, simlar to xrange в Python2:

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

порт в Python

сплавляя вместе оба ответа от @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

может быть достигнуто путем присоединения итератор на 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]

взято из курса Кайла Симпсона переосмысление асинхронного JavaScript

вот так.

это будет записывать (или перезаписывать) значение каждого индекса с номером индекса.

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]

для получения массива размере x, вот один-лайнер без использования библиотеки

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

работает в качестве

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

ниже приводится естественная адаптация питона range () функции на 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]

он поддерживает любой аргумент, который можно сравнить с 0 и stop и может быть увеличен на step. Он ведет себя идентично версии Python при использовании с числами, не превышающими Number.MAX_SAFE_INTEGER.

Пожалуйста, обратите внимание на следующие случаи:

[...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

в отличие от @Тадек это, @Волв это и @janka102 это ответ, который возвращает [],undefined или введите бесконечный цикл, когда step оценивает в 0 или NaN, эта функция генератора создает исключение, подобное поведению Python.

вы можете использовать подчеркивание библиотека. Он содержит десятки полезных функций для работы с массивами и многое другое.

дополнительно уточнено с параметрами по умолчанию 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
}

вот небольшое расширение для одного из ответов в случае, если вам нужно указать как начальную, так и конечную позицию диапазона:

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

по-прежнему нет встроенной функции, эквивалентной range(), но с последней версией - ES2015 - вы можете построить свою собственную реализацию. Вот его ограниченная версия. Ограничено, потому что он не учитывает параметр step. Только мин, макс.

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 количество объектов.

вот еще 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 имитирует питона range поведение лучше всего он может использовать генераторы JS (yield), поддерживающей как range(stop) и range(start, stop, step) варианты использования. Кроме того, pythonic ' s range функция возвращает custom built Generator объект, который поддерживает 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 для:

function range(...args) {
    if (args.length < 2) {
        return new Generator(rangeGeneratorWithStop(...args));
    }
    return new Generator(rangeGeneratorWithSartAndStopAndStep(...args));
}

const rangeGeneratorWithStop = stop => function * () {
    for (let i = 0; i < stop; i++) {
        yield i;
    }
};

const rangeGeneratorWithSartAndStopAndStep = (start, stop, step = 1) => function * () {
    for (let i = start; i < stop; i += step) {
        yield i;
    }
};

function range(...args) {
    if (args.length < 2) {
        return new Generator(rangeGeneratorWithStop(...args));
    }
    return new Generator(rangeGeneratorWithSartAndStopAndStep(...args));
}

class Generator {
    constructor(generatorFn) {
        this[Symbol.iterator] = generatorFn;
    }

    map(callbackFn) {
        const result = [];
        for (const element of this) {
            result.push(callbackFn(element));
        }
        return result;
    }

    filter(callbackFn) {
        const result = [];
        for (const element of this) {
            if (callbackFn(element)) {
                result.push(element);
            }
        }
        return result;
    }

    toArray() {
        return Array.from(this);
    }
}