¿Tiene JavaScript un método como "rango ()" para generar un rango dentro de los límites suministrados?

874

En PHP, puedes hacer ...

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

Es decir, hay una función que le permite obtener un rango de números o caracteres al pasar los límites superior e inferior.

¿Hay algo incorporado en JavaScript de forma nativa para esto? Si no, ¿cómo lo implementaría?

alex
fuente
1
Prototype.js tiene la $Rfunción, pero aparte de eso, realmente no lo creo.
Yi Jiang el
Esta pregunta (relacionada) tiene algunas respuestas excelentes: stackoverflow.com/questions/6299500/…
btk
Array.from("ABC") //['A', 'B', 'C']Esto es lo más cercano que puedo encontrar para la segunda parte de la pregunta.
Andrew_1510
@ Andrew_1510 También podría usar split("")allí
alex
1
Cuando amante atado es cero esta oneliner:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Respuestas:

1503

Números

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

Iteración de personajes

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

Iteración

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"

Como funciones

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

Como funciones escritas

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()función 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"

Navegadores antiguos que no son es6 sin una biblioteca:

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

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

(Crédito ES6 a nils petersohn y otros comentaristas)

Ben
fuente
72
Porque si es útil en cualquier lugar, probablemente sea útil en JS. (JS puede hacer cosas de tipo de programación funcional, que pueden beneficiarse de un rango (instrucción 0. Eso y mil otras razones por las que podría ser útil en algún caso semirare)
Lodewijk
55
¿Alguna idea de por qué simplemente usar (new Array(5)).map(function (value, index) { return index; })no funcionaría? Esto vuelve [undefined × 5]para mí en Chrome DevTools.
Lewis
12
@Lewis Porque una matriz definida con eso tiene ranuras vacías que no se repetirán con map()uno de sus amigos.
alex
65
Array.from (Array (5) .keys ())
nils petersohn
17
Array(5).fill()también es mapeable
nils petersohn
333

Para los números, puede usar ES6 Array.from(), que funciona en todo en estos días excepto IE:

Versión más corta:

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

Versión más larga:

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

que crea una matriz de 0 a 19 inclusive. Esto se puede acortar aún más a una de estas formas:

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

Los límites inferior y superior también se pueden especificar, por ejemplo:

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

Un artículo que describe esto con más detalle: http://www.2ality.com/2014/05/es6-array-methods.html

Kristjan Liiva
fuente
50
El primer ejemplo puede incluso simplificarse a [... Array (20) .keys ()]
Delapouite
27
Un poco más sucinto que el Array.from()método, y más rápido que ambos:Array(20).fill().map((_, i) => i)
Stu Cox
2
@Delapouite ¡Impresionante! ¡Deberías hacer esa respuesta por separado y votaré por ella! También es la respuesta perfecta a este duplicado .
foque
99
@Delapouite @jib Y esto también:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh
1
@ icc97 Sí, los linters pueden quejarse, aunque en JavaScript omitir un argumento de función definido como pasar undefined, por lo que fill()(sin argumento) no es incorrecto per se. El valor de relleno no se usa en esa solución, por lo que si lo desea, puede usar fill(0)para guardar algunos caracteres.
Stu Cox
122

Mi nueva forma favorita ( ES2015 )

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

Y si necesita una función con un stepparámetro:

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)
Kutyel
fuente
55
let range = (start, stop, step = 1) => Array (stop - start) .fill (start) .map ((x, y) => x + y * step)
rodfersou
44
@rodfersou FYI: su ejemplo está mal. stopen realidad no es la posición de parada / final sino la cuenta / distancia. (sin ofender, solo para que la gente se dé cuenta del error tipográfico)
F Lekschas
44
Para los confundidos, debido a la edición de rodfersou después del comentario de F Lekschas, su código ahora es correcto.
eedrah
1
El argumento al que pasas Array(Math.ceil((stop - start) / step) + 1), necesita +1al final, imitar realmente el comportamiento "inclusivo" de php.
Johan Dettmar
3
Esta es la respuesta principal que realmente responde a la pregunta completa de una función Javascript que implementa completamente un rangemétodo. Todos los demás que actualmente están por encima de esto (excepto lodash _.range) implementan iteradores básicos en lugar de una función de rango real con inicio, parada y paso
icc97
99

Aquí están mis 2 centavos:

function range(start, count) {
  return Array.apply(0, Array(count))
    .map((element, index) => index + start);
}
jflood.net
fuente
1
Excelente uso de funciones de alto orden.
Farzad YZ
55
Esto es realmente incorrecto porque la pregunta es pedir valores iniciales y finales. No iniciar y contar / distancia.
James Robey
73

Funciona para caracteres y números, avanzando o retrocediendo con un paso opcional.

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 .

Si lo suyo es aumentar los tipos nativos, asígnelo Array.range.

alex
fuente
53

Función de rango simple:

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

Para incorporar el tipo de datos BitInt, se puede incluir alguna verificación, asegurando que todas las variables sean iguales 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;
}

Para eliminar valores superiores a los definidos por stopejemplo range(0,5,2), incluirá 6, que no debería ser.

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
fuente
3
ADEMÁS UNO para usar y leer. El mejor fragmento de código que he visto en mucho tiempo.
monsto
1
Esto no funciona cuando step != 1, la whilecondición debe tener stepen cuenta. Mi versión actualizada con un stepvalor predeterminado : rango de funciones (inicio, parada, paso) {paso = paso || 1 var a = [inicio], b = inicio; while ((b + step) <stop) {console.log ("b:" + b + ". a:" + a + "."); b + = paso; a.push (b); } devolver a; }
daveharris
@daveharris añadí un paso predeterminado anteriormente, (step || 1).
Sr. 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
fuente
Realmente no deberías manipular métodos en el Arrayprototipo.
connectyourcharger
Este método solo funciona con enteros y caracteres. Si los parámetros son nulos, indefinidos, NaN, booleanos, matrices, objetos, etc., este método devuelve el siguiente error undefined method toUpperCase to etc:!
Victor
`` `if (typeof from! == 'number' && typeof from! == 'string') {throw new TypeError ('El primer parámetro debe ser un número o un carácter')} if (typeof to! == ' number '&& typeof to! ==' string ') {throw new TypeError (' El primer parámetro debe ser un número o un carácter ')} `` `
Victor
36

OK, en JavaScript no tenemos una range()función como PHP , por lo que necesitamos crear la función, lo cual es bastante fácil, escribo un par de funciones de una línea para usted y las separo para Números y Alfabetos de la siguiente manera:

para los números :

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

y lo llaman así:

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

para alfabetos :

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

y lo llaman así:

alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]
Alireza
fuente
2
Creo que hay errores fuera de uno en estas funciones. Debería ser Array(end - start + 1), y Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
Earcanal
24

Función práctica para hacer el truco, ejecuta el fragmento de código a continuación

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

aquí es cómo usarlo

rango (inicio, fin, paso = 1, desplazamiento = 0);

  • inclusivo - adelante range(5,10) // [5, 6, 7, 8, 9, 10]
  • inclusivo - hacia atrás range(10,5) // [10, 9, 8, 7, 6, 5]
  • paso atrás range(10,2,2) // [10, 8, 6, 4, 2]
  • exclusivo - adelante range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
  • desplazamiento - expandir range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • offset - reducir range(5,10,0,-2) // [7, 8]
  • paso - expandir range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

Esperamos que te sea útil.


Y así es como funciona.

Básicamente, primero estoy calculando la longitud de la matriz resultante y creo una matriz llena de cero a esa longitud, luego la lleno con los valores necesarios

  • (step || 1)=> Y otros como este medio utilizan el valor de stepy si no se proporciona el uso 1en vez
  • Comenzamos calculando la longitud de la matriz de resultados usando (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1)para simplificarla (diferencia * desplazamiento en ambas direcciones / pasos)
  • Después de obtener la longitud, creamos una matriz vacía con valores inicializados usando new Array(length).fill(0); marcar aquí
  • Ahora tenemos una matriz [0,0,0,..]a la longitud que queremos. Lo mapeamos y devolvemos una nueva matriz con los valores que necesitamos usandoArray.map(function() {})
  • var direction = start < end ? 1 : 0;Obviamente si startno es más pequeño que el endnecesitamos retroceder. Me refiero a ir de 0 a 5 o viceversa
  • En cada iteración, startingPoint+ stepSize* indexnos dará el valor que necesitamos
azerafati
fuente
8
Práctico, sin duda. ¿Simple? Siento disentir; independientemente de que lo conviertas en un trazador de líneas. Viniendo de Python, esto es un shock.
PascalVKooten
@PascalvKooten, sí, por supuesto, habría sido genial si hubiera un método incorporado para eso, como Python, supongo, pero este fue el más simple que pude encontrar. Y ha demostrado ser útil en mis proyectos.
azerafati
¿Publicar un fragmento de código dolorosamente complejo como ese, especialmente como una línea y sin explicación de cómo funciona? Mal ejemplo de una buena respuesta SO, independientemente de si "funciona" o no.
Madbreaks
1
@Madbreaks, sí, tienes razón. He sido ingenuo para que sea un trazador de líneas. sólo quería dar a todos una solución rápida y fácil
azerafati
22
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
Klesun
fuente
@nikkwong, _es solo un nombre de argumento en la devolución de llamada de mapeo. Ya sabes, en algunos idiomas usarías _como un nombre para señalar que la variable no se usa.
Klesun
Aquí, sin embargo, _no se pasa por los argumentos a range. Por qué no?
Nikk Wong
2
¡Muy aseado! Sin embargo, es importante tener en cuenta que no funciona en ningún IE u Opera.
Rafael Xavier
44
Esta respuesta necesita explicación, ya que es un ajuste inadecuado para SO.
Madbreaks
@RafaelXavier trabajará en IE con Array.fill () polyfill
mwag
18

Usando el operador de expansión Harmony y las funciones de flecha:

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

Ejemplo:

range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]
cPu1
fuente
esa es la mejor respuesta!
Henry H.
1
Sin embargo, no es el más rápido.
mjwrazor
¿Qué representa el símbolo de subrayado '_' en este caso?
Oleh Berehovskyi
@OlehBerehovskyi Significa un parámetro de función lambda que no tiene intención de usar realmente. Un linter que advierte sobre variables no utilizadas debe ignorarlo.
Micah Zoltu
18

--- ACTUALIZACIÓN (Gracias a @lokhmakov por la simplificación) ---

Otra versión que usa generadores ES6 (vea la excelente respuesta de Paolo Moretti con generadores ES6 ):

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

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

O, si solo necesitamos iterables, entonces:

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

--- El código ORIGINAL fue: ---

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

y

const RANGE_ITER = (a,b) => (function*(x,y){
  while (x <= y) yield x++;
})(a,b);
Hero Qu
fuente
1
Just const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov
@lokhmakov Sí, tienes razón. ¡gracias! Acabo de aplicar su código en mi respuesta.
Hero Qu
15

Investigué un poco sobre algunas funciones de rango. Consulte la comparación jsperf de las diferentes formas de realizar estas funciones. Ciertamente no es una lista perfecta o exhaustiva, pero debería ayudar :)

El ganador es...

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

Técnicamente no es el más rápido en Firefox, pero la diferencia de velocidad loca (IMHO) en Chrome lo compensa.

También es interesante observar cuánto más rápido es Chrome con estas funciones de matriz que Firefox. Chrome es al menos 4 o 5 veces más rápido .

Justin
fuente
Tenga en cuenta que esto se comparó con las funciones de rango que incluían un parámetro de tamaño de paso
binaryfunt el
15

El Javascript estándar no tiene una función incorporada para generar rangos. Varios marcos de JavaScript agregan soporte para tales características, o como otros han señalado, siempre puede implementar el suyo.

Si desea verificar dos veces, el recurso definitivo es el estándar ECMA-262 .

Mike Dinescu
fuente
Si bien estoy seguro de que es una respuesta perfectamente buena en 2010, este ya no debería considerarse el mejor enfoque. No debe extender los tipos incorporados, como Prototype.js solía hacer 👍
Dana Woodman
@DanaWoodman, gracias por mencionar esto: he actualizado la respuesta para eliminar la referencia a Prototype.js, ya que eso es bastante obsoleto en 2018
Mike Dinescu,
22
Bueno, esto no ayudó en absoluto.
Pithikos
@Pithikos Veo que esta pregunta se ha editado desde que se hizo originalmente y el OP quería saber si hay una función de rango nativa en JS.
Mike Dinescu
13

Puede usar lodash o Undescore.js range :

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

Alternativamente, si solo necesita un rango consecutivo de enteros, puede hacer algo como:

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

En ES6 rangese puede implementar con generadores :

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

Esta implementación ahorra memoria al iterar secuencias grandes, porque no tiene que materializar todos los valores en una matriz:

for (let i of range(1, oneZillion)) {
  console.log(i);
}
Paolo Moretti
fuente
La parte ES6 es ahora la respuesta correcta a esta pregunta. Recomendaría eliminar las otras partes, que están cubiertas por otras respuestas.
Joe
sin embargo, los generadores son algo extraños si se usan fuera de un bucle: x = rango (1, 10); // {} x; // {} // ¡parece un mapa vacío WTF!?! x.next (). value; // OK 1; x [3] // indefinido, solo con arreglo real
Anona112
@ Anona112 puede usar Array.frompara convertir generadores a instancias de matriz e inspeccionar la salida.
Paolo Moretti
10

Un desafío interesante sería escribir la función más corta para hacer esto. ¡Recursión al rescate!

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

Tiende a ser lento en grandes rangos, pero afortunadamente las computadoras cuánticas están a la vuelta de la esquina.

Una ventaja adicional es que es ofuscatorio. Porque todos sabemos lo importante que es ocultar nuestro código de miradas indiscretas.

Para ofuscar verdadera y completamente la función, haga esto:

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
fuente
44
Corto! = Simple, pero más simple es mejor. Aquí hay una versión más fácil de leer: const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]usando la sintaxis ES6
nafg
1
@nafg: const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. También votando la respuesta completa por el comentario.
7vujy0f0hy
10

Esta puede no ser la mejor manera. Pero si está buscando obtener un rango de números en una sola línea de código. Por ejemplo 10 - 50

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

Donde 40 es (fin - inicio) y 10 es el comienzo. Esto debería devolver [10, 11, ..., 50]

Edison D'souza
fuente
9

Codificaría algo como esto:

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]

Se comporta de manera similar al rango de Python:

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

Una implementación bastante minimalista que emplea ES6 en gran medida se puede crear de la siguiente manera, llamando especialmente la atención sobre el Array.from()método estático:

const getRange = (start, stop) => Array.from(
  new Array((stop - start) + 1),
  (_, i) => i + start
);
IsenrichO
fuente
Como nota al margen, he creado un Gist en el que hice una getRange()especie de función "mejorada" . En particular, pretendía capturar casos extremos que podrían no ser abordados en la variante básica de arriba. Además, agregué soporte para rangos alfanuméricos. En otras palabras, llamarlo con dos entradas proporcionadas como 'C'y 'K'(en ese orden) devuelve una matriz cuyos valores son el conjunto secuencial de caracteres desde la letra 'C' (inclusive) hasta la letra 'K' (exclusiva):getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
IsenrichO
no necesita la newpalabra clave
Soldeplata Saketos
8

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

Solo solicita un límite superior e inferior. Aquí creamos uno con un paso también.

Puede crear fácilmente la range()función de generador que puede funcionar como un iterador. Esto significa que no tiene que generar previamente toda la matriz.

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

Ahora es posible que desee crear algo que genere previamente la matriz desde el iterador y devuelva una lista. Esto es útil para funciones que aceptan una matriz. Para esto podemos usarArray.from()

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

Ahora puede generar una matriz estática fácilmente,

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

Pero cuando algo desea un iterador (o le da la opción de usar un iterador), también puede crear uno fácilmente.

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

Notas especiales

Evan Carroll
fuente
7

Aunque esto no es de PHP , pero una imitación de la rangede 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] 

fuente
+1 para el más rápido. con una matriz de -36768 - 36768, tomó 3 ms, el segundo lugar fue de 13 ms y tiene líneas rojas IDE.
mjwrazor
7

En cuanto a generar una matriz numérica para un rango dado, uso esto:

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]

Obviamente, no funcionará para matrices alfabéticas.

jhaskell
fuente
Establecer array = []dentro del bucle puede no darle lo que desea.
alex
@ Alex, gracias. Tienes razón, también olvidé incrementar el parámetro "inicio" en cada pasada del bucle. Ya está arreglado.
jhaskell
Todavía no producirá la salida deseada, si quiero rango 5-10, me dará [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], esperaría solo la primera mitad de esa matriz.
alex
@alex, gracias de nuevo, no había considerado una restricción de longitud basada en la entrada. Ver versión actualizada.
jhaskell
6

Uso de generadores Harmony , compatibles con todos los navegadores, excepto 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;
        }
    }
});

Ejemplos

tomar

Ejemplo 1.

take solo toma la mayor cantidad posible

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

devoluciones

[100, 105, 110, 115, 120]

Ejemplo 2

to no necesario

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

devoluciones

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

tomalo todo

Ejemplo 3

from no necesario

takeAll( range( {to: 5} ) )

devoluciones

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

Ejemplo 4

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

devoluciones

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

Ejemplo 5

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

devoluciones

["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
fuente
Editado con mis sugerencias :)
Xotic750
+1 para el enfoque. Para el punto de @ alex, no tener operaciones ternarias (especialmente no anidadas) en la forcláusula mejoraría la legibilidad aquí.
Justin Johnson
5

... más rango, usando una función de generador.

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.

Espero que esto sea útil.

John Swindin
fuente
5

A mi compañero de codegolfing se le ocurrió esto (ES6), incluido:

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

no inclusivo:

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

d3 también tiene una función de rango incorporada. Ver https://github.com/mbostock/d3/wiki/Arrays#d3_range :

d3.range ([inicio,] parada [, paso])

Genera una matriz que contiene una progresión aritmética, similar al rango incorporado de Python. Este método a menudo se usa para iterar sobre una secuencia de valores numéricos o enteros, como los índices en una matriz. A diferencia de la versión de Python, no es necesario que los argumentos sean enteros, aunque los resultados son más predecibles si se deben a la precisión de coma flotante. Si se omite el paso, el valor predeterminado es 1.

Ejemplo:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Bob Baxley
fuente
Nunca supe que existía D3. No usaré su método de rango, pero usaré este paquete.
mjwrazor
Muchas gracias. Utilizo D3 y estaba buscando un método JS nativo, sin saber que ya lo ofrecía.
cezar
4

Complete la implementación de ES6 usando la firma de rango ([inicio,] parada [, paso]):

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

Si desea pasos negativos automáticos, agregue

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

O más minimalistamente:

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

Si tienes grandes rangos, mira el enfoque del generador de Paolo Moretti

Anona112
fuente
Reemplace !stopcon typeof stop === 'undefined', luego reemplace intcon Math.floory agregue un cheque if (start > stop && step > 0)(de lo contrario, range(-3, -10)arroja una excepción en lugar de hacer algo cuerdo (ya sea voltear el signo de paso o regresar [])). De lo contrario, bien!
Ahmed Fasih
4

Hay un módulo npm bereich para eso ("bereich" es la palabra alemana para "rango"). Utiliza los iteradores modernos de JavaScript, por lo que puede usarlo de varias maneras, como:

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

También admite rangos descendentes (simplemente intercambiando miny max), y también admite pasos distintos a 1.

Descargo de responsabilidad: soy el autor de este módulo, así que tome mi respuesta con un grano de sal.

Golo Roden
fuente
4

Este también funciona a la inversa.

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
fuente