Как создать диапазон чисел от 0 до n только в ES2015?


Я всегда находил range функция отсутствует в JavaScript, поскольку она доступна в python и других? Есть ли какой-либо краткий способ создания диапазона чисел в ES2015 ?

EDIT: мой вопрос отличается от упомянутого дубликата, поскольку он специфичен для ES2015, а не ECMASCRIPT-5. Также мне нужно, чтобы диапазон начинался с 0, а не с определенного начального числа (хотя было бы хорошо, если бы это было там)

10 65

10 ответов:

вы можете использовать оператор spread для ключей только что созданного массива.

[...Array(n).keys()]

или

Array.from(Array(n).keys())

The Array.from() синтаксис необходим при работе с TypeScript

Я также нашел еще один интуитивно понятный способ с помощью Array.from:

const range = n => Array.from({length: n}, (value, key) => key)

вот этот range функция вернет все числа, начиная с 0 до n-1

модифицированная версия диапазона для поддержки start и end - это:

const range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);

EDIT Как предложил @marco6, вы можете поместить это как статический метод, если он подходит для вашего варианта использования

Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);

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

Array.range(3, 9)

Дельта

для javascript

Array.from(Array(10).keys()).map(i => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

[...Array(10).keys()].map(i => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]

Array(10).fill(0).map((v, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

Array(10).fill().map((v, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]

[...Array(10)].map((v, i) => 4 + i * 2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]

const range = (from, to, step) =>
  Array(~~((to - from) / step) + 1) // '~~' is Alternative for Math.floor()
  .fill().map((v, i) => from + i * step);

range(0, 9, 2);
//=> [0, 2, 4, 6, 8]

Array.range = (from, to, step) => Array.from({
    length: ~~((to - from) / step) + 1
  },
  (v, k) => from + k * step
);

Array.range = (from, to, step) => [...Array(~~((to - from) / step) + 1)].map(
  (v, k) => from + k * step
)
Array.range(2, 10, 2);
//=> [2, 4, 6, 8, 10]

Array.range(0, 10, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Array.range(2, 10, -1);
//=> []

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


class Range {
  constructor(total = 0, step = 1, from = 0) {
    this[Symbol.iterator] = function*() {
      for (let i = 0; i < total; yield from + i++ * step) {}
    };
  }
}

[...new Range(5)]; // Five Elements
//=> [0, 1, 2, 3, 4]
[...new Range(5, 2)]; // Five Elements With Step 2
//=> [0, 2, 4, 6, 8]
[...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
//=>[10, 8, 6, 4, 2]
[...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]

// Also works with for..of loop
for (i of new Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2

// Or
const Range = function*(total = 0, step = 1, from = 0){
  for (let i = 0; i < total; yield from + i++ * step) {}
};

Array.from(Range(5, -2, -10));
//=> [-10, -12, -14, -16, -18]
[...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]

// Also works with for..of loop
for (i of Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2

class Range2 {
  constructor(to = 0, step = 1, from = 0) {
    this[Symbol.iterator] = function*() {
      let i = 0,
        length = ~~((to - from) / step) + 1;
      while (i < length) yield from + i++ * step;
    };
  }
}
[...new Range2(5)]; // First 5 Whole Numbers
//=> [0, 1, 2, 3, 4, 5]

[...new Range2(5, 2)]; // From 0 to 5 with step 2
//=> [0, 2, 4]

[...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]

// Or 
const Range2 = function*(to = 0, step = 1, from = 0) {
    let i = 0, length = ~~((to - from) / step) + 1;
    while (i < length) yield from + i++ * step;
};


[...Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]

let even4to10 = Range2(10, 2, 8);
even4to10.next().value
//=> 8
even4to10.next().value
//=> 10
even4to10.next().value
//=> undefined

Для Typescript

interface _Iterable extends Iterable < {} > {
  length: number;
}

class _Array < T > extends Array < T > {
  static range(from: number, to: number, step: number): number[] {
    return Array.from(
      ( < _Iterable > { length: Math.floor((to - from) / step) + 1 }),
      (v, k) => from + k * step
    );
  }
}
_Array.range(0, 9, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

обновление

class _Array<T> extends Array<T> {
    static range(from: number, to: number, step: number): number[] {
        return [...Array(~~((to - from) / step) + 1)].map(
            (v, k) => from + k * step
        );
    }
}
_Array.range(0, 9, 1);

для поддержки delta

const range = (start, end, delta) => {
  return Array.from(
    {length: (end - start) / delta}, (v, k) => (k * delta) + start
  )
};

вы также можете сделать это с одним лайнером с поддержкой шага, как этот:

((from, to, step) => ((add, arr, v) => add(arr, v, add))((arr, v, add) => v < to ? add(arr.concat([v]), v + step, add) : arr, [], from))(0, 10, 1)

результат [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9].

const keys = Array(n).keys();
[...Array.from(keys)].forEach(callback);

in Typescript

вот еще один вариант, который не использует Array.

let range = (n, l=[], delta=1) => {
  if (n < 0) { 
    return l 
  }
  else {
    l.unshift(n)
    return range(n - delta, l) 
  }
}

Итак, в этом случае, было бы неплохо, если бы объект будет вести себя как объект массива с оператором spread.

например массив объект, используемый с оператором spread:

let foo = [0,1,2,3];
console.log(...foo) // returns 0 1 2 3

это работает так, потому что объект массива имеет встроенный итератор.
В нашем случае, нам нужен объект, чтобы иметь аналогичную функциональность:

[...3] //should return [0,1,2,3]

для этого мы можем просто создать итератор числа для этого цель.

Number.prototype[Symbol.iterator] = function *() {
   for(let i = 0; i <= this; i++)
       yield i;
}

Теперь можно создавать диапазоны от 0 до N с помощью оператора spread.

[...N] / / теперь возвращает 0 ... Н массив

http://jsfiddle.net/01e4xdv5/4/

ваше здоровье.

многие из этих решений основаны на создании экземпляров реальных объектов массива, которые могут выполнять работу для многих случаев, но не могут поддерживать такие случаи, как range(Infinity). Вы можете использовать простой генератор, чтобы избежать этих проблем и поддерживать бесконечные последовательности:

function* range( start, end, step = 1 ){
  if( end === undefined ) [end, start] = [start, 0];
  for( let n = start; n < end; n += step ) yield n;
}

примеры:

Array.from(range(10));     // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Array.from(range(10, 20)); // [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]

i = range(10, Infinity);
i.next(); // { value: 10, done: false }
i.next(); // { value: 11, done: false }
i.next(); // { value: 12, done: false }
i.next(); // { value: 13, done: false }
i.next(); // { value: 14, done: false }

для чисел от 0 до 5

[...Array(5).keys()];
=> [0, 1, 2, 3, 4]