Имеет ли JavaScript такой метод, как" range () " для генерации диапазона в заданных границах?

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

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

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

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

30 ответов


цифры

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

как функции

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

лодашь.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 Нильса petersohn и другие х)


для чисел вы можете использовать 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


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

    function range(start, count) {
      return Array.apply(0, Array(count))
        .map(function (element, index) { 
          return index + start;  
      });
    }

он работает для символов и чисел, идя вперед или назад с дополнительным шагом.

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

моя новая любимая форма (ES2015)

Array(10).fill(1).map((x, y) => x + y)

и если вам нужна функция с step param:

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step))
    .fill(start)
    .map((x, y) => x + y * step)

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']

ОК в JavaScript у нас нет


простой набор функций:

function range(start, stop, step){
  var a=[start], b=start;
  while(b<stop){b+=(step || 1);a.push(b)}
  return a;
};

var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);

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

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

вот как его использовать


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

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


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

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

пример:

range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]

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

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

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

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

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


интересно было бы написать короткий


Я бы код что-то вроде этого:

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]

можно использовать лодашь или 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);
}

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

const getRange = (start, stop) => Array.from(
  new Array((stop - start) + 1),
  (_, i) => i + start
);

другая версия с использованием генераторов ES6 (см. great Паоло Моретти ответить с 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 ]

или, если нам нужно только iterable, то:

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

хотя это не из 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] 

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


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


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

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]

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


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

d3.диапазон ([start,] stop [, step])

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

пример:

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

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

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.

надеюсь, это полезно.


есть модуль npm не нашли подходящие для этого ("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.

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


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

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

но это работает только при подсчете вперед (т. е. begin

const range = (b, e) => Array.apply(null, Array(Math.abs(e - b))).map((_, i) => {return b < e ? i+b : b-i;});

вот хороший короткий способ сделать это в 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()));

полная реализация 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)
}

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


Я нашел функцию диапазона JS, эквивалентную функции в PHP, и работает удивительно здорово здесь. Работает вперед и назад, и работает с целыми числами, поплавками и алфавитами!

function range(low, high, step) {
  //  discuss at: http://phpjs.org/functions/range/
  // original by: Waldo Malqui Silva
  //   example 1: range ( 0, 12 );
  //   returns 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  //   example 2: range( 0, 100, 10 );
  //   returns 2: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
  //   example 3: range( 'a', 'i' );
  //   returns 3: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
  //   example 4: range( 'c', 'a' );
  //   returns 4: ['c', 'b', 'a']

  var matrix = [];
  var inival, endval, plus;
  var walker = step || 1;
  var chars = false;

  if (!isNaN(low) && !isNaN(high)) {
    inival = low;
    endval = high;
  } else if (isNaN(low) && isNaN(high)) {
    chars = true;
    inival = low.charCodeAt(0);
    endval = high.charCodeAt(0);
  } else {
    inival = (isNaN(low) ? 0 : low);
    endval = (isNaN(high) ? 0 : high);
  }

  plus = ((inival > endval) ? false : true);
  if (plus) {
    while (inival <= endval) {
      matrix.push(((chars) ? String.fromCharCode(inival) : inival));
      inival += walker;
    }
  } else {
    while (inival >= endval) {
      matrix.push(((chars) ? String.fromCharCode(inival) : inival));
      inival -= walker;
    }
  }

  return matrix;
}

и вот уменьшенная версия:

function range(h,c,b){var i=[];var d,f,e;var a=b||1;var g=false;if(!isNaN(h)&&!isNaN(c)){d=h;f=c}else{if(isNaN(h)&&isNaN(c)){g=true;d=h.charCodeAt(0);f=c.charCodeAt(0)}else{d=(isNaN(h)?0:h);f=(isNaN(c)?0:c)}}e=((d>f)?false:true);if(e){while(d<=f){i.push(((g)?String.fromCharCode(d):d));d+=a}}else{while(d>=f){i.push(((g)?String.fromCharCode(d):d));d-=a}}return i};

для более рубинового подхода с хорошей обратной совместимостью:

range([begin], end = 0) здесь begin и end цифры

var range = function(begin, end) {
  if (typeof end === "undefined") {
    end = begin; begin = 0;
  }
  var result = [], modifier = end > begin ? 1 : -1;
  for ( var i = 0; i <= Math.abs(end - begin); i++ ) {
    result.push(begin + i * modifier);
  }
  return result;
}

примеры:

range(3); //=> [0, 1, 2, 3]
range(-2); //=> [0, -1, -2]
range(1, 2) //=> [1, 2]
range(1, -2); //=> [1, 0, -1, -2]