Есть ли у JavaScript метод, подобный "range()" для создания диапазона в пределах предоставленных границ?

В PHP вы можете сделать...

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

То есть, существует функция, которая позволяет получить диапазон чисел или символов, передавая верхнюю и нижнюю границы.

Есть ли что-то встроенное в JavaScript для этого? Если нет, как бы реализовать его?

+712
источник поделиться
57 ответов
  • 1
  • 2

Он работает для символов и цифр, перемещаясь вперед или назад с помощью дополнительного шага.

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.

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;

}

console.log(range("A", "Z", 1));
console.log(range("Z", "A", 1));
console.log(range("A", "Z", 3));


console.log(range(0, 25, 1));

console.log(range(0, 25, 5));
console.log(range(20, 5, 5));
+69
источник

чисел

[...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 Нилсу Петерсону и другим комментаторам)

+1183
источник
другие ответы

Связанные вопросы


Похожие вопросы

Для чисел вы можете использовать ES6 Array.from(), который работает во всех этих днях, кроме IE:

Более короткая версия:

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

Более длинная версия:

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

который создает массив от 0 до 19 включительно. Это может быть дополнительно сокращено до одной из следующих форм:

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

+286
источник

Моя новая любимая форма (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)
+103
источник

Вот мои 2 цента:

function range(start, count) {
  return Array.apply(0, Array(count))
    .map((element, index) => index + start);
}
+96
источник

Простая функция диапазона:

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;
}
+46
источник

Хорошо, в 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"]
+35
источник
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']
+34
источник

Handy, чтобы выполнить трюк, запустите фрагмент кода ниже

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
  • offset - expand range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • offset - shrink 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), чтобы упростить (разность * смещения в обоих направлениях/шагах)
  • После получения длины мы создаем пустой массив с инициализированными значениями, используя new Array(length).fill(0); здесь.
  • Теперь мы имеем массив [0,0,0,..] к требуемой длине. Мы сопоставляем его и возвращаем новый массив со значениями, которые нам нужны, используя Array.map(function() {})
  • var direction = start < end ? 1 : 0; Очевидно, что если start не меньше, чем end, нам нужно двигаться назад. Я имею в виду переход от 0 до 5 или наоборот
  • На каждой итерации startingPoint + stepSize * index даст нам требуемое значение
+23
источник
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
+22
источник

Использование Harmony оператора распространения и функций стрелок:

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

Пример:

range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]
+18
источник

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

Если вы хотите дважды проверить, окончательный ресурс - это стандарт ECMA-262.

+16
источник

Проведено некоторое исследование некоторых функций диапазона. Оформить сравнение jsperf различных способов выполнения этих функций. Конечно, не идеальный или исчерпывающий список, но должен помочь:)

Победитель...

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

Технически это не самый быстрый на firefox, но безумная разница в скорости (imho) на хроме компенсирует это.

Также интересно наблюдать, насколько быстрее хром с этими функциями массива, чем firefox. Chrome по крайней мере в 4 или 5 раз быстрее.

+14
источник

Вы можете использовать lodash или Undescore.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);
}
+12
источник

Другая версия с использованием генераторов ES6 (см. отличный ответ Паоло Моретти с генераторами ES6):

const RANGE = (a,b) => Array.from((function*(x,y){
  while (x <= y) yield x++;
})(a,b));

console.log(RANGE(3,7));  // [ 3, 4, 5, 6, 7 ]

Или, если нам нужна только итерация, то:

const RANGE_ITER = (a,b) => (function*(x,y){
  while (x <= y) yield x++;
})(a,b);

for (let n of RANGE_ITER(3,7)){
  console.log(n);
}

// 3
// 4
// 5
// 6
// 7
+11
источник

Интересной задачей было бы написать кратчайшую функцию для этого. Рекурсия на спасение!

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})}
+10
источник

Я бы закодировал что-то вроде этого:

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]
+9
источник

Скорее минималистическая реализация, которая в значительной степени использует ES6, может быть создана следующим образом, обращая особое внимание на статический метод Array.from():

const getRange = (start, stop) => Array.from(
  new Array((stop - start) + 1),
  (_, i) => i + start
);
+8
источник

Хотя это не 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] 
+7
источник

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
источник

Использование Генераторы гармоник, поддерживается всеми браузерами, кроме 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"]

+6
источник

Что касается создания числового массива для заданного диапазона, я использую это:

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]

Очевидно, что это не будет работать для алфавитных массивов.

+6
источник

... больше диапазона, используя функцию генератора.

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
источник

Вы можете использовать функцию lodash _.range(10) https://lodash.com/docs#range

+4
источник

У d3 также есть встроенная функция дальности. Смотрите https://github.com/mbostock/d3/wiki/Arrays#d3_range:

d3.range([start,] stop [, step])

Создает массив, содержащий арифметическую прогрессию, аналогичный встроенному диапазону Python. Этот метод часто используется для итерации последовательности числовых или целочисленных значений, таких как индексы в массиве. В отличие от версии Python, аргументы не обязательно должны быть целыми числами, хотя результаты более предсказуемы, если они обусловлены точностью с плавающей запятой. Если шаг пропущен, по умолчанию используется значение 1.

Пример:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+4
источник

Завершить реализацию ES6 с использованием диапазона ([start,] stop [, step]) подпись:

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

Если у вас есть огромные диапазоны, посмотрите на подход генератора Паоло Моретти

+4
источник

Там модуль НПМ Bereich для этого ( "Bereich" это немецкое слово "диапазон"). Он использует современные итераторы 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)) {
  // ...
}

Он также поддерживает нисходящие диапазоны (путем простого обмена min и max), а также поддерживает шаги, отличные от 1.

Отказ от ответственности: я являюсь автором этого модуля, поэтому, пожалуйста, ответьте мне с солью.

+4
источник

Это может быть не лучшим способом. Но если вы хотите получить диапазон чисел в одной строке кода. Например, 10 - 50

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

Где 40 (конец - начало) и 10 - начало. Это должно вернуть [10, 11,..., 50]

+4
источник

Я был удивлен, увидев эту тему и не вижу ничего подобного моему решению (возможно, я пропустил ответ), так что вот оно. Я использую простую функцию диапазона в синтаксисе ES6:

// [begin, end[
const range = (b, e) => Array.apply(null, Array(e - b)).map((_, i) => {return i+b;});

Но он работает только при подсчете вперед (т.е. begin < end), поэтому мы можем немного изменить его при необходимости так:

const range = (b, e) => Array.apply(null, Array(Math.abs(e - b))).map((_, i) => {return b < e ? i+b : b-i;});
+3
источник

Здесь хороший короткий способ сделать это в ES6 только с номерами (не знаю, насколько скорость его сравнивается):

Array.prototype.map.call(' '.repeat(1 + upper - lower), (v, i) => i + lower)

Для диапазона отдельных символов вы можете немного изменить его:

Array.prototype.map.call(' '.repeat(1 + upper.codePointAt() - lower.codePointAt()), (v, i) => String.fromCodePoint(i + lower.codePointAt()));
+3
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос