Чи має JavaScript такий метод, як "range ()", щоб генерувати діапазон у наданих межах?


870

У PHP ви можете зробити ...

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

Тобто є функція, яка дозволяє отримувати діапазон чисел або символів, проходячи верхню та нижню межі.

Чи є для цього щось вбудоване в JavaScript? Якщо ні, як би я це здійснив?


1
Prototype.js має $Rфункцію, але крім цього я не дуже думаю.
Yi Jiang

Це ( в зв'язку) питання має відмінні відповіді: stackoverflow.com/questions/6299500 / ...
БТК

Array.from("ABC") //['A', 'B', 'C']Це найближче, що я можу знайти для другої частини питання.
Андрій_1510

@ Andrew_1510 Ви також можете split("")там скористатися
alex

1
Коли коханець пов'язаний дорівнює нулю, цей онлайнер:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Відповіді:


1496

Числа

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

_.range()функція lodash.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]
String.fromCharCode(..._.range('A'.charCodeAt(0), 'D'.charCodeAt(0) + 1));
 => "ABCD"

Старі браузери non es6 без бібліотеки:

Array.apply(null, Array(5)).map(function (_, i) {return i;});
 => [0, 1, 2, 3, 4]

console.log([...Array(5).keys()]);

(Кредит ES6 до нуля петерсона та інших коментаторів)


72
Тому що якщо він корисний де завгодно, він, ймовірно, корисний у JS. (JS може виконувати функції функціонального програмування, які можуть скористатися діапазоном (заява 0. Це та тисяча інших причин може бути корисним у якомусь напівредкому випадку)
Lodewijk,

5
Будь-яка ідея, чому просто використання (new Array(5)).map(function (value, index) { return index; })не буде працювати? Це повертається [undefined × 5]для мене в Chrome DevTools.
Льюїс

12
@Lewis Оскільки масив, визначений для цього, має порожні слоти, які не будуть повторені разом із map()одним із його друзів.
alex

65
Array.from (Array (5) .keys ())
nils petersohn

17
Array(5).fill()також відображається
nils petersohn

332

Для чисел ви можете використовувати 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


50
Перший приклад можна навіть спростити до [... Array (20) .keys ()]
Delapouite

27
Трохи більш лаконічний, ніж Array.from()метод, і швидше, ніж обидва:Array(20).fill().map((_, i) => i)
Стю Кокс

2
@Delapouite Awesome! Ви повинні зробити це окремою відповіддю, і я за це проголосую! Це також ідеальна відповідь на цей дублікат .
липень

9
@Delapouite @jib І це також:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh

1
@ icc97 Так, лінери можуть скаржитися, хоча в JavaScript пропускаючи аргумент функції, визначений як той самий, що передає undefined, тому fill()(без аргументу) сам по собі не помиляється . У цьому рішенні значення заливки не використовується, тому, якщо вам подобається, ви можете використати fill(0)для збереження кількох символів.
Стю Кокс

122

Моя нова улюблена форма ( 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)

5
нехай діапазон = (старт, стоп, крок = 1) => Масив (стоп - старт). заповнення (старт) .карта ((х, у) => х + у * крок)
rodfersou

4
@rodfersou FYI: ваш приклад неправильний. stopнасправді не положення стоп / кінець, а кількість / відстань. (без образи, лише для того, щоб люди усвідомили друкарську помилку)
F Lekschas

4
Для плутанини - через редакцію rodfersou після коментаря F Lekschas, його код тепер правильний.
еедра

1
Аргумент, який ви передаєте Array(Math.ceil((stop - start) / step) + 1), потребує +1кінця, щоб дійсно імітувати поведінку php "включно".
Йохан Деттмар

3
Це головна відповідь, яка насправді відповідає на повне запитання функції Javascript, яка повністю реалізує rangeметод. Усі інші, що перебувають вище цього (крім лодаша _.range), реалізують основні ітератори, а не фактичну функцію діапазону із запуском, зупинкою та кроком
icc97

99

Ось мої 2 копійки:

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

1
Відмінне використання функцій високого порядку.
Farzad YZ

5
Це насправді неправильно, оскільки питання задає початкові та кінцеві значення. Не починати & рахувати / відстань.
Джеймс Робі

73

Він працює для символів та чисел, йдучи вперед або назад з необов'язковим кроком.

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.


53

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

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

Для видалення значень, вищих, ніж визначено, stopнаприклад, range(0,5,2)буде включено 6, чого не повинно бути.

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

3
ПЛЮС UNO для зручного використання та читання. Найкращий фрагмент коду, який я бачив вже давно.
Монсто

1
Це не працює , коли step != 1, то whileумова необхідно приймати stepдо уваги. Моя оновлена ​​версія зі stepзначенням за замовчуванням : діапазон функцій (запуск, зупинка, крок) {step = step || 1 var a = [старт], b = початок; while ((b + крок) <стоп) {console.log ("b:" + b + ". a:" + a + "."); b + = крок; a.push (b); } повернути a; }
daveharris

@daveharris я додав крок за замовчуванням вище, (step || 1).
Містер Polywhirl

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

Ви дійсно не повинні застосовувати методи Arrayпрототипу на прототипі.
connectyourcharger

Цей метод працює лише з цілими числами та символами. Якщо параметри є null, undefined, NaN, boolean, array, object тощо, цей метод повертає таку помилку undefined method toUpperCase to etc:!
Віктор

`` `if (typeof from! == 'number' && typeof from! == 'string') {киньте новий TypeError ('Першим параметром має бути число чи символ')} if (typeof to! == ' число '&& typeof to! ==' string ') {киньте новий TypeError (' Першим параметром має бути число чи символ ')} `` `
Віктор

36

Гаразд, у 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"]

2
Я думаю, що в цих функціях є похибки один за одним. Повинно бути Array(end - start + 1)і Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
вулканал

24

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

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
  • зміщення - розширення range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • зміщення - скорочення 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* indexwill дає нам необхідне значення

8
Зручно, звичайно. Простий? Дозволю собі не погодитися; незалежно від того, що ви зробите це одним вкладишем. Похід з Python - це шок.
PascalVKooten

@PascalvKooten, так, звичайно, було б чудово, якби був вбудований метод для такого, як python, я думаю, але це був найпростіший, до якого я міг зайти. І це виявилося корисним у моїх проектах.
azerafati

Опублікувати подібний фрагмент кодового коду, особливо як однолінійку та не пояснюючи, як це працює? Поганий приклад хорошої відповіді ТА, незалежно від того, працює він чи ні.
Madbreaks

1
@Madbreaks, так, ти маєш рацію. Я був наївний, щоб зробити це одним лайнером. просто хотів дати всім швидке та просте рішення
азерафати

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

@nikkwong, _це лише назва аргументу у зворотному зв’язку відображення. Ви знаєте, в деяких мовах ви б використовували _як ім'я, щоб вказати, що змінна не використовується.
Клесун

Тут, однак, _не передано аргументи до range. Чому ні?
nikk wong

2
Дуже акуратно! Хоча, важливо відзначити, що він не працює ні в одному IE, ні в Opera.
Рафаель Ксав'є

4
Ця відповідь потребує пояснення, оскільки вона вважає, що вона погано підходить для ЗП.
Madbreaks

@RafaelXavier буде працювати над IE з поліфайлом Array.fill ()
mwag

18

Використання операторів розгортання Harmony та стрілок:

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

Приклад:

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

це найкраща відповідь!
Генрі Х.

1
Але не найшвидший.
mjwrazor

Що означає символ "_" підкреслення в цьому випадку?
Олег Береховський,

@OlehBerehovskyi Це означає параметр функції лямбда, який ви не маєте наміру реально використовувати. Вкладиш, який попереджає про невикористані змінні, повинен ігнорувати його.
Міхей Золту

18

--- ОНОВЛЕННЯ (спасибі @lokhmakov за спрощення) ---

Інша версія з використанням генераторів ES6 (див. Чудову відповідь Паоло Моретті з генераторами ES6 ):

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

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

Або, якщо нам потрібен лише ітерабельний, то:

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

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

// 3
// 4
// 5
// 6
// 7

--- ОРГІНАЛЬНИЙ код був: ---

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

і

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

1
Просто const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
лохмаков

@lokhmakov Так, ви праві. Дякую тобі! Щойно застосував ваш код у моїй відповіді.
Hero Qu

15

Провели деякі дослідження деяких функцій діапазону. Ознайомтесь із порівнянням 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 разів швидший .


Зауважте, що це порівнювали з функціями діапазону, які включали параметр розміру кроку
binaryfunt

15

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

Якщо ви хочете двічі перевірити, остаточним ресурсом є ECMA-262 .


Хоча я впевнений, що в 2010 році ідеально хороша відповідь, це більше не слід вважати найкращим підходом. Вам не слід розширювати вбудовані типи, як це робило прототип.js 👍
Дана Вудман,

@DanaWoodman дякую за те, що це підняло - я оновив відповідь, щоб зняти посилання на Prototype.js, оскільки це справді значно застаріло у 2018 році
Майк Дінеску,

20
Ну, це зовсім не допомогло.
Пітікос

@Pithikos Я бачу, що це питання було відредаговано, оскільки його спочатку задавали, і ОП хотіла дізнатися, чи є функція нативного діапазону в JS.
Майк Дінеску

13

Ви можете використовувати 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);
}

Частина ES6 тепер є правильною відповіддю на це питання. Я рекомендую видалити інші частини, які охоплені іншими відповідями.
Joews

генератори дещо дивні, якщо використовуються поза циклом, хоча: x = range (1, 10); // {} x; // {} // виглядає як порожня карта WTF!?! x.next (). значення; // OK 1; x [3] // невизначено, лише з реальним масивом
Anona112

@ Anona112 ви можете використовувати Array.fromдля перетворення генераторів для масивів екземплярів та перевірки результатів.
Паоло Моретті

10

Цікавим завданням було б написати найкоротшу функцію для цього. Рекурсія на допомогу!

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

4
Короткий! = Простий, але простіший - краще. Ось простіша для читання версія: з const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]використанням синтаксису
ES6

1
@nafg: const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Також підтримуючи всю відповідь за коментар.
7vujy0f0hy

10

Це може бути не найкращим способом. Але якщо ви хочете отримати діапазон чисел в одному рядку коду. Наприклад 10 - 50

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

Де 40 - це кінець - старт, а 10 - початок. Це має повернутись [10, 11, ..., 50]


9

Я б кодував щось подібне:

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]

8

Досить мінімалістична реалізація, яка широко використовує ES6, може бути створена наступним чином, привертаючи особливу увагу до Array.from()статичного методу:

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

В якості побічної ноти я створив Gist, в якому я зробив "розширену" getRange()функцію сортів. Зокрема, я мав на меті зафіксувати крайові випадки, які можуть бути без розгляду у варіанті з голими кістками вище. Крім того, я додав підтримку буквено-цифрових діапазонів. Іншими словами, викликаючи його з двома вхідними входами, як-от 'C'і 'K'(у тому порядку) повертає масив, значення якого є послідовним набором символів з літери "С" (включно) через букву "К" (виключно):getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
IsenrichO

вам не потрібно newключове слово
Soldeplata Saketos

8

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

Хоча це не від 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] 

+1 для найшвидших. з масивом -36768 - 36768, зайняв 3 мс, 2 місце посіло 13 мс і має червоні лінії IDE.
mjwrazor

7

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

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]

Очевидно, він не працює для алфавітних масивів.


Встановлення array = []всередині циклу може не дати тобі, що ти хочеш.
алекс

@ Алекс, дякую. Ви маєте рацію, я також забув збільшити параметр "start" на кожному проході циклу. Це зараз виправлено.
jhaskell

Він все одно не дасть бажаного виводу, якщо я хочу діапазон 5-10, він дасть мені [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], я б очікував лише першої половини цього масиву.
alex

@ Алекс, ще раз дякую, я не вважав обмеження довжини на основі вхідних даних. Дивіться оновлену версію.
jhaskell

6

Використання генераторів Harmony , підтримуваних усіма браузерами, крім 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"]


Відредаговано моїми пропозиціями :)
Xotic750

+1 за підхід. На думку @ alex, відсутність потрійних операцій (особливо не вкладених) у forпункті, покращить читабельність тут.
Джастін Джонсон

5

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

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

Мій співробітник з кодового гольфу придумав це (ES6), включно:

(s,f)=>[...Array(f-s+1)].map((e,i)=>i+s)

не включено:

(s,f)=>[...Array(f-s)].map((e,i)=>i+s)


4

d3 також має вбудовану функцію діапазону. Дивіться https://github.com/mbostock/d3/wiki/Arrays#d3_range :

d3.range ([пуск,] зупинка [, крок])

Створює масив, що містить арифметичну прогресію, аналогічну вбудованому діапазону Python. Цей метод часто використовується для перебору послідовності числових чи цілих значень, таких як індекси в масив. На відміну від версії Python, аргументи не повинні бути цілими числами, хоча результати є більш передбачуваними, якщо вони обумовлені точністю з плаваючою комою. Якщо крок опущено, він за замовчуванням дорівнює 1.

Приклад:

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

Я ніколи не знав, що D3 існує. Не збирається використовувати метод їх діапазону, але буде використовувати цей пакет.
mjwrazor

Дуже дякую. Я використовую D3 і шукав рідний метод JS, не знаючи, що I D3 це вже пропонує.
cezar

4

Повна реалізація ES6 за допомогою підпису діапазону ([пуск,] зупинка [, крок]):

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

Якщо у вас величезний діапазон, подивіться на генераторський підхід Паоло Моретті


Замініть !stopна typeof stop === 'undefined', потім замініть intна Math.floorі додайте чек if (start > stop && step > 0)(інакше range(-3, -10)викидає виняток замість того, щоб зробити щось здорове (або перевернути знак кроку, або повернутися [])). Інакше добре!
Ахмед Фасіх

4

Для цього є npm-модуль 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

Цей працює також і в зворотному напрямку.

const range = ( a , b ) => Array.from( new Array( b > a ? b - a : a - b ), ( x, i ) => b > a ? i + a : a - i );

range( -3, 2 ); // [ -3, -2, -1, 0, 1 ]
range( 1, -4 ); // [ 1, 0, -1, -2, -3 ]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.