JavaScript ha un metodo come "range ()" per generare un intervallo entro i limiti forniti?


873

In PHP, puoi fare ...

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

Cioè, c'è una funzione che ti consente di ottenere un intervallo di numeri o caratteri passando i limiti superiore e inferiore.

C'è qualcosa di nativo in JavaScript nativamente per questo? In caso contrario, come lo implementerei?


1
Prototype.js ha la $Rfunzione, ma a parte questo non credo proprio.
Yi Jiang,

Questa domanda (correlata) ha alcune risposte eccellenti: stackoverflow.com/questions/6299500/…
btk

Array.from("ABC") //['A', 'B', 'C']Questa è la cosa più vicina che posso trovare per la seconda parte della domanda.
Andrew_1510,

@ Andrew_1510 Potresti usare split("")anche lì
alex

1
Quando l'amante è pari a zero, questo interlinea:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk,

Risposte:


1502

Numeri

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

Iterazione del personaggio

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

Iterazione

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"

Come funzioni

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

Come funzioni digitate

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

Vecchi browser non es6 senza libreria:

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

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

(Credito ES6 a nils petersohn e altri commentatori)


72
Perché se è utile ovunque è probabilmente utile in JS. (JS può fare cose del tipo di programmazione funzionale, che possono beneficiare di un intervallo (istruzione 0. Questo e mille altri motivi potrebbe essere utile in alcuni casi semirare)
Lodewijk,

5
Qualche idea sul perché il semplice utilizzo (new Array(5)).map(function (value, index) { return index; })non funzioni? Questo ritorna [undefined × 5]per me in Chrome DevTools.
Lewis,

12
@Lewis Perché un array definito con quello ha slot vuoti che non verranno ripetuti con map()o con uno dei suoi amici.
alex,

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

17
Array(5).fill()è anche mappabile
nils petersohn

333

Per i numeri puoi usare ES6 Array.from(), che funziona in tutto in questi giorni tranne IE:

Versione più corta:

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

Versione più lunga:

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

che crea un array compreso tra 0 e 19 inclusi. Questo può essere ulteriormente abbreviato in una di queste forme:

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

È possibile specificare anche i limiti inferiore e superiore, ad esempio:

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

Un articolo che lo descrive in modo più dettagliato: http://www.2ality.com/2014/05/es6-array-methods.html


50
Il primo esempio può anche essere semplificato in [... Array (20) .keys ()]
Delapouite,

27
Leggermente più succinto del Array.from()metodo e più veloce di entrambi:Array(20).fill().map((_, i) => i)
Stu Cox,

2
@Delapouite Awesome! Dovresti fare una risposta separata e voterò per questo! È anche la risposta perfetta a questo duplicato .
braccio

9
@Delapouite @jib E anche questo:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh,

1
@ icc97 Sì, i linter possono lamentarsi, anche se in JavaScript omettere un argomento di funzione definito come passare undefined, quindi fill()(senza argomenti) non è di per sé sbagliato . Il valore di riempimento non viene utilizzato in quella soluzione, quindi se lo desideri puoi utilizzare fill(0)per salvare alcuni caratteri.
Stu Cox,

122

La mia nuova forma preferita ( ES2015 )

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

E se hai bisogno di una funzione con un stepparametro:

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)

5
let range = (start, stop, step = 1) => Array (stop - start) .fill (start) .map ((x, y) => x + y * step)
rodfersou

4
@rodfersou FYI: il tuo esempio è sbagliato. stopin realtà non è la posizione di arresto / fine ma il conteggio / la distanza. (senza offesa, solo per rendere le persone consapevoli
dell'errore di

4
Per i confusi - a causa della modifica di Rodfersou dopo il commento di F Lekschas, il suo codice è ora corretto.
edera

1
L'argomento in cui passi Array(Math.ceil((stop - start) / step) + 1), +1alla fine , ha bisogno di imitare davvero il comportamento "inclusivo" di php.
Johan Dettmar,

3
Questa è la risposta migliore che in realtà risponde alla domanda completa di una funzione Javascript che implementa completamente un rangemetodo. Tutti gli altri attualmente al di sopra di questo (tranne quelli di lodash _.range) implementano iteratori di base piuttosto che una funzione di portata effettiva con start, stop e step
icc97

99

Ecco i miei 2 centesimi:

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

1
Ottimo utilizzo di funzioni di alto ordine.
Farzad YZ,

5
Questo è in realtà sbagliato perché la domanda richiede valori di inizio e fine. Non iniziare e contare / distanza.
James Robey,

73

Funziona con caratteri e numeri, andando avanti o indietro con un passaggio opzionale.

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 .

Se il miglioramento dei tipi nativi è la tua passione, assegnalo a Array.range.


53

Funzione range semplice:

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

Per incorporare il tipo di dati BitInt è possibile includere alcuni controlli, assicurando che tutte le variabili siano uguali 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;
}

Per rimuovere valori superiori a quelli definiti da stopes. range(0,5,2)Includerà 6, che non dovrebbe essere.

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
PLUS UNO per usabile e leggibile. Il miglior frammento di codice che vedo da molto tempo.
monsto

1
Questo non funziona quando step != 1, la whilecondizione deve essere presa stepin considerazione. La mia versione aggiornata con un stepvalore predefinito : intervallo di funzioni (start, stop, step) {step = step || 1 var a = [inizio], b = inizio; while ((b + step) <stop) {console.log ("b:" + b + ". a:" + a + "."); b + = passo; a.push (b); } restituisce a; }
daveharris,

@daveharris Ho aggiunto un gradino sopra di default, (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']

Non dovresti davvero usare metodi jerry-rig sul Arrayprototipo.
connectyourcharger

Questo metodo funziona solo con numeri interi e caratteri. Se i parametri sono null, indefiniti, NaN, booleani, array, oggetti, ecc., Questo metodo restituisce il seguente errore undefined method toUpperCase to etc:!
Victor,

`` `if (typeof from! == 'number' && typeof from! == 'string') {throw new TypeError ('Il primo parametro dovrebbe essere un numero o un carattere')} if ((typeof to! == ' number '&& typeof to! ==' string ') {throw new TypeError (' Il primo parametro dovrebbe essere un numero o un carattere ')} `` `
Victor

36

OK, in JavaScript non abbiamo una range()funzione come PHP , quindi dobbiamo creare la funzione che è abbastanza facile, scrivo un paio di funzioni a una riga per te e le separiamo per Numeri e Alfabeti come di seguito:

per i numeri :

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

e chiamalo come:

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

per alfabeti :

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

e chiamalo come:

alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]

2
Penso che ci siano errori off-by-one in queste funzioni. Dovrebbe essere Array(end - start + 1), e Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
earcanal

24

Pratica funzione per fare il trucco, esegui lo snippet di codice qui sotto

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

ecco come usarlo

intervallo (Start, End, Step = 1, Offset = 0);

  • inclusivo - avanti range(5,10) // [5, 6, 7, 8, 9, 10]
  • inclusivo - indietro range(10,5) // [10, 9, 8, 7, 6, 5]
  • passo indietro range(10,2,2) // [10, 8, 6, 4, 2]
  • esclusivo - forward range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
  • offset - espandi range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • offset - restringimento range(5,10,0,-2) // [7, 8]
  • step - espandi range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

spero che lo trovi utile.


Ed ecco come funziona.

Fondamentalmente sto prima calcolando la lunghezza della matrice risultante e creare una matrice riempita di zero per quella lunghezza, quindi riempirla con i valori necessari

  • (step || 1)=> E altri come questo significa usare il valore di stepe se non è stato fornito usare 1invece
  • Iniziamo calcolando la lunghezza dell'array dei risultati usando (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1)per renderlo più semplice (differenza * offset in entrambe le direzioni / passi)
  • Dopo aver ottenuto la lunghezza, quindi creiamo un array vuoto con valori inizializzati usando il new Array(length).fill(0); controllo qui
  • Ora abbiamo un array [0,0,0,..]per la lunghezza che vogliamo. Ci mappiamo su di esso e restituiamo un nuovo array con i valori di cui abbiamo bisogno utilizzandoArray.map(function() {})
  • var direction = start < end ? 1 : 0;Ovviamente se startnon è più piccolo di quello endche dobbiamo spostare indietro. Intendo passare da 0 a 5 o viceversa
  • Ad ogni iterazione, startingPoint+ stepSize* indexci darà il valore di cui abbiamo bisogno

8
Pratico, sicuramente. Semplice? Mi permetto di dissentire; a prescindere dal fatto che tu ne faccia uno solo. Venendo da Python questo è uno shock.
PascalVKooten

@PascalvKooten, sì, certo, sarebbe stato fantastico se ci fosse un metodo integrato per quello come Python, immagino, ma questo è stato il più semplice che potessi trovare. E ha dimostrato di essere utile nei miei progetti.
Azerafati,

Pubblicare uno snippet di codice dolorosamente complesso come quello, specialmente come one-liner e senza spiegazioni su come funziona? Scarso esempio di una buona risposta SO, indipendentemente dal fatto che "funzioni" o meno.
Madbreaks,

1
@Madbreaks, sì hai ragione. Sono stato ingenuo per renderlo una fodera. volevo solo dare a tutti una soluzione semplice e veloce
azerafati il

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

@nikkwong, the _è solo un nome di argomento nel callback del mapping. Sai, in alcune lingue useresti _come un nome per sottolineare che la variabile non è usata.
Klesun,

Qui però, _non viene passato attraverso gli argomenti a range. Perchè no?
nikk wong,

2
Molto pulito! Tuttavia, è importante notare che non funziona su IE o Opera.
Rafael Xavier,

4
Questa risposta ha bisogno di spiegazioni, in quanto non è adatta per SO.
Madbreaks,

@RafaelXavier lavorerà su IE con Array.fill () polyfill
mwag

18

Utilizzo dell'operatore di diffusione Harmony e delle funzioni freccia:

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

Esempio:

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

questa è la risposta migliore!
Henry H.

1
Non è il più veloce però.
mjwrazor,

Cosa significa in questo caso il trattino basso "_"?
Oleh Berehovskyi,

@OlehBerehovskyi Indica un parametro della funzione lambda che non si intende utilizzare. Un linter che avverte di variabili non utilizzate dovrebbe ignorarlo.
Micah Zoltu,

18

--- AGGIORNAMENTO (Grazie a @lokhmakov per la semplificazione) ---

Un'altra versione che utilizza generatori ES6 (vedi la risposta di Paolo Moretti con i generatori ES6 ):

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

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

Oppure, se abbiamo solo bisogno di iterabile, allora:

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

--- Il codice ORGINAL era: ---

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

e

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

1
Solo const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov il

@lokhmakov Sì, hai ragione. grazie! Ho appena applicato il tuo codice nella mia risposta.
Hero Qu

15

Ha fatto delle ricerche su alcune varie funzioni di portata. Guarda il confronto jsperf dei diversi modi per eseguire queste funzioni. Certamente non un elenco perfetto o completo, ma dovrebbe aiutare :)

Il vincitore è...

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

Tecnicamente non è il più veloce su Firefox, ma la folle differenza di velocità (imho) su Chrome lo compensa.

Un'altra interessante osservazione è quanto Chrome sia più veloce con queste funzioni di array rispetto a Firefox. Chrome è almeno 4 o 5 volte più veloce .


Si noti che questo è stato confrontato con le funzioni di intervallo che includevano un parametro di dimensione del passo
binaryfunt

15

Javascript standard non ha una funzione integrata per generare intervalli. Diversi framework javascript aggiungono supporto per tali funzionalità, o come altri hanno sottolineato, puoi sempre creare il tuo.

Se si desidera ricontrollare, la risorsa definitiva è lo standard ECMA-262 .


Anche se sono sicuro di avere una risposta perfettamente valida nel 2010, questo non dovrebbe più essere considerato l'approccio migliore. Non dovresti estendere i tipi predefiniti, come Prototype.js tendeva a fare 👍
Dana Woodman,

@DanaWoodman grazie per averlo sollevato - ho aggiornato la risposta per eliminare il riferimento a Prototype.js poiché è praticamente obsoleto nel 2018
Mike Dinescu,

21
Bene, questo non ha aiutato affatto.
Pithikos,

@Pithikos Vedo che questa domanda è stata modificata da quando è stata originariamente posta e l'OP voleva sapere se esiste una funzione di intervallo nativa in JS.
Mike Dinescu,

13

Puoi usare lodash o Undescore.js range :

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

In alternativa, se hai solo bisogno di un intervallo consecutivo di numeri interi puoi fare qualcosa del tipo:

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

In ES6 rangepuò essere implementato con generatori :

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

Questa implementazione consente di risparmiare memoria durante l'iterazione di sequenze di grandi dimensioni, poiché non deve materializzare tutti i valori in un array:

for (let i of range(1, oneZillion)) {
  console.log(i);
}

La parte ES6 è ora la risposta corretta a questa domanda. Consiglierei di rimuovere le altre parti, che sono coperte da altre risposte.
joews

i generatori sono in qualche modo strani se usati al di fuori di un ciclo: x = range (1, 10); // {} x; // {} // sembra una mappa vuota WTF!?! x.next (). value; // OK 1; x [3] // undefined, solo con array reale
Anona112

@ Anona112 è possibile utilizzare Array.fromper convertire i generatori in istanze di array e ispezionare l'output.
Paolo Moretti,

10

Una sfida interessante sarebbe quella di scrivere la funzione più breve per farlo. Ricorsione in soccorso!

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

Tende ad essere lento su grandi distanze, ma per fortuna i computer quantistici sono dietro l'angolo.

Un ulteriore vantaggio è che è offuscato. Perché sappiamo tutti quanto sia importante nascondere il nostro codice da occhi indiscreti.

Per offuscare veramente e completamente la funzione, fai questo:

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

4
Breve! = Semplice, ma più semplice è meglio. Ecco una versione più facile da leggere const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]
:,

1
@nafg: const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Valorizza anche l'intera risposta per il commento.
7vujy0f0hy

10

Questo potrebbe non essere il modo migliore. Ma se stai cercando di ottenere un intervallo di numeri in una singola riga di codice. Ad esempio 10 - 50

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

Dove 40 è (end - start) e 10 è l'inizio. Questo dovrebbe restituire [10, 11, ..., 50]


9

Vorrei codificare qualcosa del genere:

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]

Si comporta in modo simile all'intervallo Python:

>>> range(-4,2)
[-4, -3, -2, -1, 0, 1]

8

Un'implementazione piuttosto minimalista che impiega fortemente ES6 può essere creata come segue, attirando particolare attenzione al Array.from()metodo statico:

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

Come nota a margine, ho creato un Gist in cui ho fatto una getRange()sorta di funzione "potenziata" . In particolare, ho mirato a catturare casi limite che potrebbero non essere affrontati nella variante di ossa nude sopra. Inoltre, ho aggiunto il supporto per intervalli alfanumerici. In altre parole, chiamandolo con due input forniti come 'C'e 'K'(in quell'ordine) restituisce un array i cui valori sono l'insieme sequenziale di caratteri dalla lettera 'C' (compresa) attraverso la lettera 'K' (esclusiva):getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
IsenrichO

non hai bisogno della newparola chiave
Soldeplata Saketos,

8

range(start,end,step): Con Iteratori ES6

Chiedi solo un limite superiore e inferiore. Qui ne creiamo uno anche con un passo.

È possibile creare facilmente una range()funzione del generatore che può funzionare come iteratore. Ciò significa che non è necessario pre-generare l'intero array.

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

Ora potresti voler creare qualcosa che pre-genera l'array dall'iteratore e restituisce un elenco. Ciò è utile per le funzioni che accettano un array. Per questo possiamo usareArray.from()

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

Ora puoi generare facilmente un array statico,

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

Ma quando qualcosa desidera un iteratore (o ti dà la possibilità di usare un iteratore) puoi facilmente crearne uno anche tu.

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

Note speciali


7

Anche se questo non proviene da PHP , ma un'imitazione di rangeda 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 per il più veloce. con un array di -36768-36768, ha impiegato 3 ms, il 2 ° posto era 13 ms e ha linee rosse IDE.
mjwrazor,

7

Per quanto riguarda la generazione di un array numerico per un determinato intervallo, utilizzo questo:

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]

Ovviamente, non funzionerà con le matrici alfabetiche.


L'impostazione array = []all'interno del loop potrebbe non darti quello che vuoi.
alex

@alex, grazie. Hai ragione, ho anche dimenticato di incrementare il parametro "start" su ogni passaggio del loop. Ora è riparato.
Jhaskell,

Non produrrà ancora l'output desiderato, se voglio l'intervallo 5-10, mi darà [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], mi aspetterei solo la prima metà di quell'array.
alex

@alex, grazie ancora, non avevo considerato un vincolo di lunghezza basato sull'input. Vedi versione aggiornata.
jhaskell,

6

Utilizzando i generatori Harmony , supportati da tutti i browser tranne 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;
        }
    }
});

Esempi

prendere

Esempio 1.

take richiede solo il massimo che può ottenere

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

ritorna

[100, 105, 110, 115, 120]

Esempio 2

to non necessario

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

ritorna

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

prendi tutto

Esempio 3

from non necessario

takeAll( range( {to: 5} ) )

ritorna

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

Esempio 4

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

ritorna

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

Esempio 5

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

ritorna

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


Modificato con i miei suggerimenti :)
Xotic750

+1 per l'approccio. Al punto di @ alex, non avere operazioni ternarie (specialmente non annidate) nella forclausola migliorerebbe la leggibilità qui.
Justin Johnson,

5

... più portata, usando una funzione di generatore.

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.

Spero sia utile.


5

Il mio collega codegolfing ha escogitato questo (ES6), compreso:

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

non compreso:

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


4

d3 ha anche una funzione di portata integrata. Vedi https://github.com/mbostock/d3/wiki/Arrays#d3_range :

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

Genera un array contenente una progressione aritmetica, simile all'intervallo incorporato di Python. Questo metodo viene spesso utilizzato per scorrere su una sequenza di valori numerici o interi, come gli indici in un array. A differenza della versione di Python, gli argomenti non devono essere numeri interi, sebbene i risultati siano più prevedibili se dovuti alla precisione in virgola mobile. Se il passaggio viene omesso, il valore predefinito è 1.

Esempio:

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

Non ho mai saputo che D3 esistesse. Non utilizzerà il metodo range ma utilizzerà questo pacchetto.
mjwrazor,

Grazie mille. Uso D3 e cercavo un metodo JS nativo, non sapendo che D3 lo offre già.
Cezar

4

Completa implementazione di ES6 usando la firma range ([start,] stop [, step]):

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

Se si desidera un stepping negativo automatico, aggiungere

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

O più minimalisticamente:

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

Se hai gamme enormi guarda l'approccio del generatore di Paolo Moretti


Sostituisci !stopcon typeof stop === 'undefined', quindi sostituisci intcon Math.floore aggiungi un segno di spunta if (start > stop && step > 0)(altrimenti, range(-3, -10)genera un'eccezione invece di fare qualcosa di sano (lanciando il segno del passaggio o ritornando [])). Altrimenti bene!
Ahmed Fasih,

4

C'è un modulo npm da bereich per questo ("bereich" è la parola tedesca per "range"). Utilizza i moderni iteratori di JavaScript, quindi puoi usarlo in vari modi, come:

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

Supporta anche intervalli decrescenti (semplicemente scambiando mine max) e supporta anche passaggi diversi da 1.

Disclaimer: sono l'autore di questo modulo, quindi per favore prendi la mia risposta con un pizzico di sale.


4

Questo funziona anche al contrario.

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 ]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.