Ответ 1
Вы можете использовать оператор распространения на клавишах только что созданного массива.
[...Array(n).keys()]
или
Array.from(Array(n).keys())
Array.from()
необходим при работе с TypeScript
Я всегда обнаружил, что функция range
отсутствует в JavaScript, поскольку она доступна в python и других? Есть ли какой-нибудь краткий способ генерации диапазона чисел в ES2015?
EDIT: мой вопрос отличается от указанного дубликата, поскольку он специфичен для ES2015, а не ECMASCRIPT-5. Также мне нужен диапазон, начинающийся с 0, а не на конкретный начальный номер (хотя было бы хорошо, если бы это было там)
Вы можете использовать оператор распространения на клавишах только что созданного массива.
[...Array(n).keys()]
или
Array.from(Array(n).keys())
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);
ИЗМЕНИТЬ Как было предложено @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, 6, 8, 10, 12, 14, 16, 18, 20, 22]
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
Для машинописи
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);
редактировать
class _Array<T> extends Array<T> {
static range(from: number, to: number, step: number): number[] {
return Array.from(Array(~~((to - from) / step) + 1)).map(
(v, k) => from + k * step
);
}
}
_Array.range(0, 9, 1);
Для чисел от 0 до 5
[...Array(5).keys()];
=> [0, 1, 2, 3, 4]
Поддержка дельта
const range = (start, end, delta) => {
return Array.from(
{length: (end - start) / delta}, (v, k) => (k * delta) + start
)
};
Итак, в этом случае было бы неплохо, если бы объект Number вел себя как объект Array с оператором распространения.
Например, объект Array, используемый с оператором распространения:
let foo = [0,1,2,3];
console.log(...foo) // returns 0 1 2 3
Он работает так, потому что объект Array имеет встроенный итератор.
В нашем случае нам нужен объект Number, чтобы иметь аналогичную функциональность:
[...3] //should return [0,1,2,3]
Для этого мы можем просто создать Number iterator для этой цели.
Number.prototype[Symbol.iterator] = function *() {
for(let i = 0; i <= this; i++)
yield i;
}
Теперь можно создавать диапазоны от 0 до N с помощью оператора спреда.
[... N]//теперь возвращает массив 0... N
http://jsfiddle.net/01e4xdv5/4/
Приветствия.
Многие из этих решений основаны на создании реальных объектов Array, которые могут выполнять работу во многих случаях, но не могут поддерживать такие случаи, как 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 }
Вы также можете сделать это с помощью одного лайнера с поддержкой шагов, подобной этой:
((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);
в Typescript
Здесь другой вариант, который не использует Array
.
let range = (n, l=[], delta=1) => {
if (n < 0) {
return l
}
else {
l.unshift(n)
return range(n - delta, l)
}
}
Вы можете использовать функцию генератора, которая создает диапазон лениво только тогда, когда это необходимо:
function* range(x, y) {
while (true) {
if (x <= y)
yield x++;
else
return null;
}
}
const infiniteRange = x =>
range(x, Infinity);
console.log(
Array.from(range(1, 10)) // [1,2,3,4,5,6,7,8,9,10]
);
console.log(
infiniteRange(1000000).next()
);
Эта функция вернет целочисленную последовательность.
const integerRange = (start, end, n = start, arr = []) =>
(n === end) ? [...arr, n]
: integerRange(start, end, start < end ? n + 1 : n - 1, [...arr, n]);
$> intSequence(1, 1)
<- Array [ 1 ]
$> intSequence(1, 3)
<- Array(3) [ 1, 2, 3 ]
$> intSequence(3, -3)
<- Array(7) [ 3, 2, 1, 0, -1, -2, -3 ]