Hoe genereer je een bereik van getallen van 0 tot n, alleen in ES2015?

Ik heb altijd ontdekt dat de functie rangeontbreekt in JavaScript omdat deze beschikbaar is in python en andere? Is er een beknopte manier om een ​​reeks getallen te genereren in ES2015?

BEWERKEN: MIJN vraag verschilt van het genoemde duplicaat omdat het specifiek is voor ES2015 en niet voor ECMASCRIPT-5. Ik heb ook nodig dat het bereik begint bij 0 en geen specifiek startnummer (hoewel het goed zou zijn als dat er is)


Antwoord 1, autoriteit 100%

U kunt de spread-operator gebruiken op de toetsen van een nieuw gemaakte array.

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

of

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

De syntaxis Array.from()is nodig als u met TypeScript werkt


Antwoord 2, autoriteit 35%

Ik heb ook nog een intuïtieve manier gevonden om Array.fromte gebruiken:

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

Deze functie rangeretourneert nu alle getallen beginnend van 0 tot n-1

Een aangepaste versie van het bereik om starten endte ondersteunen is:

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

BEWERKEN
Zoals gesuggereerd door @marco6, kun je dit als een statische methode gebruiken als dit geschikt is voor jouw gebruik

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

en gebruik het als

Array.range(3, 9)

Antwoord 3, autoriteit 13%

Met Delta/Step

kleinste en oneliner

[...Array(N)].map((_, i) => from + i * step);

Voorbeelden en andere alternatieven

[...Array(10)].map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10)).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
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((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array(10).fill().map((_, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]

Bereik Functie:

const range = (from, to, step) =>
  [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
range(0, 9, 2);
//=> [0, 2, 4, 6, 8]
// can also assign range function as static method in Array class (but not recommended )
Array.range = (from, to, step) =>
  [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * 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]

als iterators

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

Alleen als generatoren

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
// Lazy loaded way
const number0toInf = Range(Infinity);
number0toInf.next().value;
//=> 0
number0toInf.next().value;
//=> 1
// ...

Van-Naar met stappen/delta

iterators gebruiken

class Range2 {
  constructor(to = 0, step = 1, from = 0) {
    this[Symbol.iterator] = function* () {
      let i = 0,
        length = Math.floor((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]

generatoren gebruiken

const Range2 = function* (to = 0, step = 1, from = 0) {
  let i = 0,
    length = Math.floor((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, 4);
even4to10.next().value;
//=> 4
even4to10.next().value;
//=> 6
even4to10.next().value;
//=> 8
even4to10.next().value;
//=> 10
even4to10.next().value;
//=> undefined

Voor typoscript

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

Bijwerken

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

Bewerken

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

Antwoord 4, autoriteit 7%

Voor nummers 0 tot 5

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

Antwoord 5, autoriteit 5%

Veel van deze oplossingen bouwen voort op het instantiëren van echte Array-objecten, die de klus voor veel gevallen kunnen klaren, maar die geen ondersteuning bieden voor gevallen zoals range(Infinity). Je zou een eenvoudige generator kunnen gebruiken om deze problemen te vermijden en oneindige reeksen te ondersteunen:

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

Voorbeelden:

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 }

Antwoord 6, autoriteit 4%

Dus in dit geval zou het fijn zijn als het Number-object zich zou gedragen als een Array-object met de spread-operator.

Bijvoorbeeld Arrayobject gebruikt met de spread-operator:

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

Het werkt zo omdat het Array-object een ingebouwde iterator heeft.
In ons geval hebben we een Numberobject nodig om een ​​vergelijkbare functionaliteit te hebben:

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

Om dat te doen, kunnen we voor dat doel eenvoudig Number iterator maken.

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

Het is nu mogelijk om bereiken van 0 tot N te creëren met de spread-operator.

[…N] // geeft nu 0 … N array terug

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

Proost.


Antwoord 7

Je kunt een generatorfunctie gebruiken, die het bereik alleen lui creëert als dat nodig is:

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

Snippet uitvouwen


Antwoord 8

Bereik met stap ES6, dat werkt vergelijkbaar met python list(range(start, stop[, step])):

const range = (start, stop, step = 1) => {
  return [...Array(stop - start).keys()]
    .filter(i => !(i % Math.round(step)))
    .map(v => start + v)
}

Voorbeelden:

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

Antwoord 9

Delta ondersteunen

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

Antwoord 10

Wat dacht je van gewoon in kaart brengen ….

Array(n).map((value, index) ….) is 80% van de weg ernaartoe. Maar om de een of andere vreemde reden werkt het niet. Maar er is een oplossing.

Array(n).map((v,i) => i) // does not work
Array(n).fill().map((v,i) => i) // does dork

Voor een bereik

Array(end-start+1).fill().map((v,i) => i + start) // gives you a range

Vreemd, deze twee iterators retourneren hetzelfde resultaat: Array(end-start+1).entries()en Array(end-start+1).fill().entries()


Antwoord 11

Je kunt het ook doen met een oneliner met opstapondersteuning zoals deze:

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

Het resultaat is [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9].

Other episodes