Verfügt JavaScript über eine Methode wie "range ()", um einen Bereich innerhalb der angegebenen Grenzen zu generieren?

871

In PHP können Sie ...

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

Das heißt, es gibt eine Funktion, mit der Sie eine Reihe von Zahlen oder Zeichen abrufen können, indem Sie die oberen und unteren Grenzen überschreiten.

Ist hierfür nativ etwas in JavaScript integriert? Wenn nicht, wie würde ich es implementieren?

Alex
quelle
1
Prototype.js hat die $RFunktion, aber ansonsten denke ich nicht wirklich.
Yi Jiang
Diese (verwandte) Frage hat einige ausgezeichnete Antworten: stackoverflow.com/questions/6299500/…
btk
Array.from("ABC") //['A', 'B', 'C']Dies ist das Nächste, was ich für den zweiten Teil der Frage finden kann.
Andrew_1510
@ Andrew_1510 könnten Sie split("")es auch
alex
1
Wenn der gebundene Liebhaber Null ist, ist dieser Oneliner:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Antworten:

1499

Zahlen

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

Zeicheniteration

String.fromCharCode(...[...Array('D'.charCodeAt(0) - 'A'.charCodeAt(0) + 1).keys()].map(i => i + 'A'.charCodeAt(0)));
 => "ABCD"

Wiederholung

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"

Als Funktionen

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

Als getippte Funktionen

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

lodash.js _.range()Funktion

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

Alte Nicht-Es6-Browser ohne Bibliothek:

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

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

(ES6 Kredit an Nils Petersohn und andere Kommentatoren)

Ben
quelle
72
Denn wenn es irgendwo nützlich ist, ist es wahrscheinlich in JS nützlich. (JS kann funktionale Programmieraufgaben ausführen, die von einem Bereich profitieren können (0-Anweisung. Das und tausend andere Gründe, warum es in einem Semirare-Fall nützlich sein könnte)
Lodewijk,
5
Irgendeine Idee, warum die einfache Verwendung (new Array(5)).map(function (value, index) { return index; })nicht funktionieren würde? Dies kehrt [undefined × 5]für mich in Chrome DevTools zurück.
Lewis
12
@ Lewis Weil ein damit definiertes Array leere Slots hat, die nicht mit map()oder einem seiner Freunde wiederholt werden .
Alex
65
Array.from (Array (5) .keys ())
Nils Petersohn
17
Array(5).fill()ist auch kartierbar
nils petersohn
333

Für Zahlen können Sie ES6 verwenden Array.from(), das heutzutage in allen Funktionen außer IE funktioniert :

Kürzere Version:

Array.from({length: 20}, (x,i) => i);

Längere Version:

Array.from(new Array(20), (x,i) => i)

Dadurch wird ein Array von 0 bis einschließlich 19 erstellt. Dies kann weiter auf eine dieser Formen verkürzt werden:

Array.from(Array(20).keys())
// or
[...Array(20).keys()]

Unter- und Obergrenzen können ebenfalls angegeben werden, zum Beispiel:

Array.from(new Array(20), (x,i) => i + *lowerBound*)

Ein Artikel, der dies ausführlicher beschreibt: http://www.2ality.com/2014/05/es6-array-methods.html

Kristjan Liiva
quelle
50
Das erste Beispiel kann sogar vereinfacht werden, um [... Array (20) .keys ()]
Delapouite
27
Etwas prägnanter als die Array.from()Methode und schneller als beide:Array(20).fill().map((_, i) => i)
Stu Cox
2
@ Delapouite Super! Sie sollten dies als separate Antwort festlegen, und ich werde dafür stimmen! Es ist auch die perfekte Antwort auf dieses Duplikat .
Fock
9
@ Delapouite @jib Und das auch:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh
1
@ icc97 Ja, Linters können sich beschweren, obwohl in JavaScript ein Funktionsargument weggelassen wird, das als dasselbe wie das Übergeben definiert ist undefined, so dass fill()(ohne Argument) per se nicht falsch ist . Der Füllwert wird in dieser Lösung nicht verwendet. Wenn Sie möchten, können Sie fill(0)einige Zeichen speichern.
Stu Cox
122

Meine neue Lieblingsform ( ES2015 )

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

Und wenn Sie eine Funktion mit einem stepParameter benötigen:

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)
Kutyel
quelle
5
let range = (start, stop, step = 1) => Array (stop - start) .fill (start) .map ((x, y) => x + y * step)
rodfersou
4
@rodfersou FYI: Ihr Beispiel ist falsch. stopist eigentlich nicht die Stopp- / Endposition, sondern Anzahl / Entfernung. (nichts für ungut, nur um die Leute auf den Tippfehler aufmerksam zu machen)
F Lekschas
4
Für die Verwirrten - aufgrund von Rodfersous Bearbeitung nach F Lekschas 'Kommentar ist sein Code jetzt korrekt.
Eedrah
1
Das Argument, auf das Sie eingehen Array(Math.ceil((stop - start) / step) + 1), braucht das +1am Ende, um das "inklusive" Verhalten von PHP wirklich nachzuahmen.
Johan Dettmar
3
Dies ist die beste Antwort, die tatsächlich die vollständige Frage einer Javascript-Funktion beantwortet, die eine rangeMethode vollständig implementiert . Alle anderen derzeit darüber liegenden (mit Ausnahme von lodashs _.range) implementieren grundlegende Iteratoren anstelle einer tatsächlichen Bereichsfunktion mit Start, Stopp und Schritt
icc97
99

Hier sind meine 2 Cent:

function range(start, count) {
  return Array.apply(0, Array(count))
    .map((element, index) => index + start);
}
jflood.net
quelle
1
Hervorragende Verwendung von Funktionen hoher Ordnung.
Farzad YZ
5
Dies ist tatsächlich falsch, da die Frage nach Start- und Endwerten fragt. Nicht starten & zählen / Distanz.
James Robey
73

Es funktioniert für Zeichen und Zahlen und geht mit einem optionalen Schritt vorwärts oder rückwärts.

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 .

Wenn es Ihr Ding ist, native Typen zu erweitern, weisen Sie es zu Array.range.

Alex
quelle
53

Einfache Bereichsfunktion:

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

Um den BitInt-Datentyp einzubeziehen, kann eine Prüfung durchgeführt werden, um sicherzustellen, dass alle Variablen gleich sind 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;
}

Um Werte zu entfernen, die höher sind als durch stopzB definiert, range(0,5,2)wird eingeschlossen 6, was nicht sein sollte.

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;
}
Remi
quelle
3
PLUS UNO für brauchbar und lesbar. Das beste Code-Snippet, das ich seit langer Zeit gesehen habe.
Montag,
1
Dies funktioniert nicht, wenn step != 1die whileBedingung stepberücksichtigt werden muss. Meine aktualisierte Version mit einem Standardwert step: Funktionsbereich (Start, Stopp, Schritt) {Schritt = Schritt || 1 var a = [Start], b = Start; while ((b + Schritt) <Stopp) {console.log ("b:" + b + ". a:" + a + "."); b + = Schritt; a.push (b); } return a; }
Daveharris
@ Daveharris Ich habe oben einen Standardschritt hinzugefügt (step || 1).
Mr. 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']
kennebec
quelle
Sie sollten wirklich keine Jerry-Rig-Methoden auf den ArrayPrototyp anwenden .
Verbinden Sie Ihr Ladegerät
Diese Methode funktioniert nur mit ganzen Zahlen und Zeichen. Wenn die Parameter null, undefiniert, NaN, boolesch, Array, Objekt usw. sind, gibt diese Methode den folgenden Fehler zurück : undefined method toUpperCase to etc!
Victor
`` `if (typeof from! == 'number' && typeof from! == 'string') {neuen TypeError auslösen ('Der erste Parameter sollte eine Zahl oder ein Zeichen sein')} if (typeof to! == ' number '&& typeof to! ==' string ') {throw new TypeError (' Der erste Parameter sollte eine Zahl oder ein Zeichen sein ')} `` `
Victor
36

OK, in JavaScript haben wir keine range()Funktion wie PHP , daher müssen wir die Funktion erstellen, die recht einfach ist. Ich schreibe einige einzeilige Funktionen für Sie und trenne sie wie folgt für Zahlen und Alphabete :

für Zahlen :

function numberRange (start, end) {
  return new Array(end - start).fill().map((d, i) => i + start);
}

und nenne es wie:

numberRange(5, 10); //[5, 6, 7, 8, 9]

für Alphabete :

function alphabetRange (start, end) {
  return new Array(end.charCodeAt(0) - start.charCodeAt(0)).fill().map((d, i) => String.fromCharCode(i + start.charCodeAt(0)));
}

und nenne es wie:

alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]
Alireza
quelle
2
Ich denke, es gibt einzelne Fehler in diesen Funktionen. Sollte sein Array(end - start + 1)und Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
Earcanal
24

Praktische Funktion, um den Trick auszuführen, führen Sie das folgende Code-Snippet aus

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

Hier erfahren Sie, wie Sie es verwenden

Bereich (Start, Ende, Schritt = 1, Versatz = 0);

  • inklusive - vorwärts range(5,10) // [5, 6, 7, 8, 9, 10]
  • inklusive - rückwärts range(10,5) // [10, 9, 8, 7, 6, 5]
  • Schritt zurück range(10,2,2) // [10, 8, 6, 4, 2]
  • exklusiv - vorwärts range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
  • Offset - erweitern range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • Offset - schrumpfen range(5,10,0,-2) // [7, 8]
  • Schritt - erweitern range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

Ich hoffe, Sie finden es nützlich.


Und so funktioniert es.

Grundsätzlich berechne ich zuerst die Länge des resultierenden Arrays und erstelle ein mit Null gefülltes Array auf diese Länge und fülle es dann mit den erforderlichen Werten

  • (step || 1)=> Und andere wie dieses bedeuten, verwenden Sie den Wert von stepund wenn es nicht bereitgestellt wurde, verwenden Sie 1stattdessen
  • Wir beginnen mit der Berechnung der Länge des Ergebnisarrays (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1), um es einfacher auszudrücken (Differenz * Versatz in beide Richtungen / Schritte).
  • Nachdem wir die Länge ermittelt haben, erstellen wir mit check hier ein leeres Array mit initialisierten Wertennew Array(length).fill(0);
  • Jetzt haben wir ein Array [0,0,0,..]mit der gewünschten Länge. Wir ordnen es zu und geben ein neues Array mit den Werten zurück, die wir benötigenArray.map(function() {})
  • var direction = start < end ? 1 : 0;Wenn startes nicht kleiner als das ist end, müssen wir uns natürlich rückwärts bewegen. Ich meine von 0 auf 5 oder umgekehrt
  • Bei jeder Iteration gibt uns startingPoint+ stepSize* indexden Wert, den wir brauchen
Azerafati
quelle
8
Mit Sicherheit praktisch. Einfach? Ich bin anderer Ansicht; unabhängig davon, dass Sie es zu einem Einzeiler machen. Aus Python zu kommen, ist ein Schock.
PascalVKooten
@PascalvKooten, ja, natürlich wäre es großartig gewesen, wenn es eine eingebaute Methode dafür wie Python gegeben hätte, aber dies war die einfachste, die ich bekommen konnte. Und es hat sich in meinen Projekten als nützlich erwiesen.
Azerafati
Ein so schmerzhaft komplexes Code-Snippet wie dieses veröffentlichen, insbesondere als Einzeiler und ohne Erklärung, wie es funktioniert? Schlechtes Beispiel für eine gute SO-Antwort, unabhängig davon, ob sie "funktioniert" oder nicht.
Madbreaks
1
@ Madbreaks, ja du hast recht. Ich war naiv, es zu einem Einzeiler zu machen. wollte nur allen eine schnelle und einfache Lösung geben
azerafati
22
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
Klesun
quelle
@nikkwong, das _ist nur ein Name des Arguments im Mapping-Rückruf. Sie wissen, in einigen Sprachen würden Sie das _als Namen verwenden, um darauf hinzuweisen, dass die Variable nicht verwendet wird.
Klesun
Hier _wird jedoch nicht durch die Argumente an weitergegeben range. Warum nicht?
Nikk Wong
2
Sehr gepflegt! Es ist jedoch wichtig zu beachten, dass es in keinem IE oder Opera funktioniert.
Rafael Xavier
4
Diese Antwort muss erklärt werden, da sie für SO schlecht geeignet ist.
Madbreaks
@ RafaelXavier wird am IE mit Array.fill ()
polyfill arbeiten
18

Verwenden der Harmony Spread Operator- und Pfeilfunktionen:

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

Beispiel:

range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]
cPu1
quelle
Das ist die beste Antwort!
Henry H.
1
Nicht der schnellste.
Mjwrazor
Was bedeutet das Unterstreichungssymbol '_' in diesem Fall?
Oleh Berehovskyi
@OlehBerehovskyi Dies bedeutet einen Lambda-Funktionsparameter, den Sie nicht tatsächlich verwenden möchten. Ein Linter, der vor nicht verwendeten Variablen warnt, sollte dies ignorieren.
Micah Zoltu
18

--- UPDATE (Danke an @lokhmakov für die Vereinfachung) ---

Eine andere Version mit ES6-Generatoren (siehe die großartige Antwort von Paolo Moretti mit ES6-Generatoren ):

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

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

Oder wenn wir nur iterable brauchen, dann:

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

--- ORGINAL Code war: ---

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

und

const RANGE_ITER = (a,b) => (function*(x,y){
  while (x <= y) yield x++;
})(a,b);
Held Qu
quelle
1
Just const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov
@lokhmakov Ja, du hast recht. Vielen Dank! Habe gerade deinen Code in meiner Antwort angewendet.
Hero Qu
15

Ich habe einige Untersuchungen zu verschiedenen Bereichsfunktionen durchgeführt. Testen Sie den jsperf-Vergleich der verschiedenen Möglichkeiten, diese Funktionen auszuführen . Sicher keine perfekte oder vollständige Liste, sollte aber helfen :)

Der Gewinner ist...

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

Technisch gesehen ist es nicht das schnellste auf Firefox, aber der verrückte Geschwindigkeitsunterschied (imho) auf Chrom macht das wieder wett.

Interessant ist auch, wie viel schneller Chrom mit diesen Array-Funktionen ist als Firefox. Chrome ist mindestens vier- oder fünfmal schneller .

Justin
quelle
Beachten Sie, dass dies mit Bereichsfunktionen verglichen wurde, die einen Schrittgrößenparameter enthielten
binaryfunt
15

Das Standard-Javascript verfügt nicht über eine integrierte Funktion zum Generieren von Bereichen. Mehrere Javascript-Frameworks bieten Unterstützung für solche Funktionen, oder wie andere bereits betont haben, können Sie jederzeit Ihre eigenen rollen.

Wenn Sie dies noch einmal überprüfen möchten, ist die endgültige Ressource der ECMA-262-Standard .

Mike Dinescu
quelle
Ich bin mir sicher, dass dies 2010 eine vollkommen gute Antwort ist, aber dies sollte nicht länger als der beste Ansatz angesehen werden. Sie sollten eingebaute Typen nicht erweitern, wie dies Prototype.js normalerweise tat
Dana
@ DanaWoodman danke, dass Sie dies angesprochen haben - Ich habe die Antwort aktualisiert, um den Verweis auf Prototype.js herauszunehmen, da dies 2018 tatsächlich ziemlich veraltet ist
Mike Dinescu
21
Nun, das hat überhaupt nicht geholfen.
Pithikos
@Pithikos Ich sehe, dass diese Frage bearbeitet wurde, seit sie ursprünglich gestellt wurde, und das OP wollte wissen, ob es in JS eine native Bereichsfunktion gibt.
Mike Dinescu
13

Sie können lodash oder Undescore.js verwenden range :

var range = require('lodash/range')
range(10)
// -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Wenn Sie nur einen aufeinanderfolgenden Bereich von Ganzzahlen benötigen, können Sie alternativ Folgendes tun:

Array.apply(undefined, { length: 10 }).map(Number.call, Number)
// -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

In ES6 rangekann mit Generatoren implementiert werden :

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

Diese Implementierung spart Speicher beim Iterieren großer Sequenzen, da nicht alle Werte in einem Array materialisiert werden müssen:

for (let i of range(1, oneZillion)) {
  console.log(i);
}
Paolo Moretti
quelle
Der ES6-Teil ist jetzt die richtige Antwort auf diese Frage. Ich würde empfehlen, die anderen Teile zu entfernen, die von anderen Antworten abgedeckt werden.
Joews
Generatoren sind etwas seltsam, wenn sie außerhalb einer Schleife verwendet werden: x = range (1, 10); // {} x; // {} // sieht aus wie eine leere Karte WTF!?! x.next (). value; // OK 1; x [3] // undefiniert, nur mit echtem Array
Anona112
@ Anona112 können Sie verwenden Array.from, um Generatoren in Array-Instanzen zu konvertieren und die Ausgabe zu überprüfen.
Paolo Moretti
10

Eine interessante Herausforderung wäre es, die kürzeste Funktion dafür zu schreiben . Rückfall zur Rettung!

function r(a,b){return a>b?[]:[a].concat(r(++a,b))}

Neigt dazu, auf großen Entfernungen langsam zu sein, aber zum Glück sind Quantencomputer gleich um die Ecke.

Ein zusätzlicher Bonus ist, dass es verschleiert. Weil wir alle wissen, wie wichtig es ist, unseren Code vor neugierigen Blicken zu verbergen.

Gehen Sie folgendermaßen vor, um die Funktion wirklich und vollständig zu verschleiern:

function r(a,b){return (a<b?[a,b].concat(r(++a,--b)):a>b?[]:[a]).sort(function(a,b){return a-b})}
Rick Hitchcock
quelle
4
Kurz! = Einfach, aber einfacher ist besser. Hier ist eine leichter zu lesende Version: const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]mit ES6-Syntax
nafg
1
@nafg : const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Stimmen Sie auch die gesamte Antwort für den Kommentar ab.
7vujy0f0hy
10

Dies ist möglicherweise nicht der beste Weg. Wenn Sie jedoch eine Reihe von Zahlen in einer einzigen Codezeile suchen. Zum Beispiel 10 - 50

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

Wobei 40 ist (Ende - Start) und 10 der Anfang ist. Dies sollte [10, 11, ..., 50] zurückgeben.

Edison D'souza
quelle
9

Ich würde so etwas codieren:

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]

Es verhält sich ähnlich wie der Python-Bereich:

>>> range(-4,2)
[-4, -3, -2, -1, 0, 1]
Sasha Zezulinsky
quelle
8

Eine eher minimalistische Implementierung, die stark ES6 verwendet, kann wie folgt erstellt werden, wobei besondere Aufmerksamkeit auf die Array.from()statische Methode gelenkt wird:

const getRange = (start, stop) => Array.from(
  new Array((stop - start) + 1),
  (_, i) => i + start
);
IsenrichO
quelle
Als Randnotiz habe ich einen Kern erstellt, in dem ich eine Art "erweiterte" getRange()Funktion erstellt habe. Insbesondere wollte ich Randfälle erfassen, die in der obigen Bare-Bones-Variante möglicherweise nicht behandelt wurden. Zusätzlich habe ich Unterstützung für alphanumerische Bereiche hinzugefügt. Mit anderen Worten, wenn Sie es mit zwei bereitgestellten Eingaben wie 'C'und 'K'(in dieser Reihenfolge) aufrufen , wird ein Array zurückgegeben, dessen Werte der sequentielle Zeichensatz vom Buchstaben 'C' (einschließlich) bis zum Buchstaben 'K' (exklusiv) sind:getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
IsenrichO
Sie brauchen das newSchlüsselwort nicht
Soldeplata Saketos
8

range(start,end,step): Mit ES6-Iteratoren

Sie fragen nur nach einer Ober- und Untergrenze. Hier erstellen wir auch eine mit einem Schritt.

Sie können einfach eine range()Generatorfunktion erstellen , die als Iterator fungieren kann. Dies bedeutet, dass Sie nicht das gesamte Array vorgenerieren müssen.

function * range ( start, end, step = 1 ) {
  let state = start;
  while ( state < end ) {
    yield state;
    state += step;
  }
  return;
};

Jetzt möchten Sie möglicherweise etwas erstellen, das das Array aus dem Iterator vorgeneriert und eine Liste zurückgibt. Dies ist nützlich für Funktionen, die ein Array akzeptieren. Dafür können wir verwendenArray.from()

const generate_array = (start,end,step) =>
  Array.from( range(start,end,step) );

Jetzt können Sie ganz einfach ein statisches Array generieren.

const array1 = generate_array(1,10,2);
const array1 = generate_array(1,7);

Wenn jedoch ein Iterator gewünscht wird (oder Sie die Möglichkeit haben, einen Iterator zu verwenden), können Sie auch einfach einen erstellen.

for ( const i of range(1, Number.MAX_SAFE_INTEGER, 7) ) {
  console.log(i)
}

Besondere Hinweise

Evan Carroll
quelle
7

Dies ist zwar nicht von PHP , sondern eine Nachahmung rangevon 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] 

quelle
+1 für den schnellsten. mit einem Array von -36768 - 36768 dauerte 3 ms, der 2. Platz war 13 ms und hat rote IDE-Linien.
Mjwrazor
7

Um ein numerisches Array für einen bestimmten Bereich zu generieren, verwende ich Folgendes:

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]

Offensichtlich funktioniert es nicht für alphabetische Arrays.

jhaskell
quelle
Das Einstellen array = []innerhalb der Schleife gibt Ihnen möglicherweise nicht das, was Sie wollen.
Alex
@alex, danke. Sie haben Recht, ich habe auch vergessen, den "Start" -Parameter bei jedem Durchgang der Schleife zu erhöhen. Es ist jetzt behoben.
Jhaskell
Es wird immer noch nicht die gewünschte Ausgabe erzeugt. Wenn ich einen Bereich von 5 bis 10 möchte, würde es mir geben [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], ich würde nur die erste Hälfte dieses Arrays erwarten.
Alex
@alex, nochmals vielen Dank, ich hatte keine Längenbeschränkung aufgrund von Eingaben berücksichtigt. Siehe aktualisierte Version.
Jhaskell
6

Verwenden von Harmony-Generatoren , die von allen Browsern außer IE11 unterstützt werden :

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

Beispiele

nehmen

Beispiel 1.

take braucht nur so viel wie es nur geht

take(10, range( {from: 100, step: 5, to: 120} ) )

kehrt zurück

[100, 105, 110, 115, 120]

Beispiel 2.

to nicht notwendig

take(10, range( {from: 100, step: 5} ) )

kehrt zurück

[100, 105, 110, 115, 120, 125, 130, 135, 140, 145]

Nimm alles

Beispiel 3.

from nicht notwendig

takeAll( range( {to: 5} ) )

kehrt zurück

[0, 1, 2, 3, 4, 5]

Beispiel 4.

takeAll( range( {to: 500, step: 100} ) )

kehrt zurück

[0, 100, 200, 300, 400, 500]

Beispiel 5.

takeAll( range( {from: 'z', to: 'a'} ) )

kehrt zurück

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

Janus Troelsen
quelle
Bearbeitet mit meinen Vorschlägen :)
Xotic750
+1 für den Ansatz. Nach Ansicht von @ alex würde das Fehlen von ternären Operationen (insbesondere nicht verschachtelt) in der forKlausel die Lesbarkeit hier verbessern.
Justin Johnson
5

... mehr Reichweite mit einer Generatorfunktion.

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.

Hoffe das ist nützlich.

John Swindin
quelle
5

Mein Codegolf-Mitarbeiter hat sich das ausgedacht (ES6), einschließlich:

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

nicht inklusive:

(s,f)=>[...Array(f-s)].map((e,i)=>i+s)
Marc Sloth Eastman
quelle
4

d3 hat auch eine eingebaute Bereichsfunktion. Siehe https://github.com/mbostock/d3/wiki/Arrays#d3_range :

d3.range ([start,] stop [, step])

Erzeugt ein Array mit einer arithmetischen Folge, ähnlich dem in Python integrierten Bereich. Diese Methode wird häufig verwendet, um eine Folge von numerischen oder ganzzahligen Werten, z. B. die Indizes, in einem Array zu durchlaufen. Im Gegensatz zur Python-Version müssen die Argumente keine Ganzzahlen sein, obwohl die Ergebnisse vorhersehbarer sind, wenn sie auf Gleitkomma-Genauigkeit zurückzuführen sind. Wenn der Schritt weggelassen wird, wird standardmäßig 1 verwendet.

Beispiel:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Bob Baxley
quelle
Ich wusste nie, dass D3 existiert. Sie werden ihre Bereichsmethode nicht verwenden, aber dieses Paket verwenden.
Mjwrazor
Ich danke dir sehr. Ich benutze D3 und suchte nach einer nativen JS-Methode, ohne zu wissen, dass ich D3 bereits anbiete.
Cezar
4

Schließen Sie die ES6-Implementierung mit der Signatur des Bereichs ([Start,] Stopp [, Schritt]) ab:

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

Wenn Sie ein automatisches negatives Steppen wünschen, fügen Sie hinzu

if(stop<start)step=-Math.abs(step)

Oder minimalistischer:

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

Wenn Sie große Reichweiten haben, schauen Sie sich den Generatoransatz von Paolo Moretti an

Anona112
quelle
Ersetzen !stopdurch typeof stop === 'undefined', dann ersetzen intdurch Math.floorund fügen Sie einen Scheck hinzu if (start > stop && step > 0)(andernfalls wird range(-3, -10)eine Ausnahme ausgelöst, anstatt etwas Vernünftiges zu tun (entweder das Zeichen des Schritts umdrehen oder zurückkehren [])). Ansonsten gut!
Ahmed Fasih
4

Dafür gibt es ein npm-Modul bereich ("bereich" ist das deutsche Wort für "range"). Es verwendet moderne JavaScript-Iteratoren, sodass Sie es auf verschiedene Arten verwenden können, z.

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)) {
  // ...
}

Es unterstützt auch absteigende Bereiche (durch einfaches Austauschen von minund max) und andere Schritte als 1.

Haftungsausschluss: Ich bin der Autor dieses Moduls. Bitte nehmen Sie meine Antwort mit einem Körnchen Salz.

Golo Roden
quelle
4

Dieser funktioniert auch umgekehrt.

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 ]
Rocco Ghielmini
quelle