Cómo crear una matriz que contiene 1 ... N


1163

Estoy buscando alternativas a las siguientes para crear una matriz de JavaScript que contenga de 1 a N, donde N solo se conoce en tiempo de ejecución.

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

Para mí, parece que debería haber una manera de hacer esto sin el bucle.


224
Después de leer toda esta página, he llegado a la conclusión de que su propio bucle for simple es el más simple, más legible y menos propenso a errores.
Kokodoko

Si alguien necesita algo más avanzado, creé una lib de node.js que hace esto para números, letras, rangos negativos / positivos, etc. github.com/jonschlinkert/fill-range . Se usa en github.com/jonschlinkert/braces para la expansión de llaves y github.com/jonschlinkert/micromatch para patrones glob
jonschlinkert

1
Debería editar para decir "Cómo crear una matriz de longitud N" en lugar de "... que contiene 1 ... N", esto último implica que habrá elementos con valores de 1 a N
Steven Landow

77
@StevenLandow ¿por qué debería cambiar el nombre de OP? ¿Quiere una matriz con valores 1 ... N?
Andre Elrico

Buena pregunta, buen título, (un poco) respuestas tontas.
Bitterblue

Respuestas:


381

Si obtengo lo que buscas, quieres una matriz de números 1..nque luego puedas recorrer.

Si esto es todo lo que necesitas, ¿puedes hacer esto en su lugar?

var foo = new Array(45); // create an empty array with length 45

entonces cuando quieras usarlo ... (no optimizado, solo por ejemplo)

for(var i = 0; i < foo.length; i++){
  document.write('Item: ' + (i + 1) + ' of ' + foo.length + '<br/>'); 
}

por ejemplo, si no necesita almacenar nada en la matriz, solo necesita un contenedor de la longitud correcta sobre el que pueda iterar ... esto podría ser más fácil.

Véalo en acción aquí: http://jsfiddle.net/3kcvm/


44
me impresionó que hayas logrado formular mi pregunta mejor de lo que pude, de hecho estás en lo correcto, ya que en reflexión todo lo que necesito es una serie de números que luego pueda recorrer :) Gracias por tu respuesta.
Godders

147
@Godders: Si esto es lo que estás buscando, ¿por qué necesitas una matriz? Un simple var n = 45;y luego bucle 1..nsería suficiente.
casablanca

3
@Godders: para tener en cuenta, si desea disminuir el tamaño de la matriz después de crearla a la longitud M, simplemente use foo.length = M--- La información de corte se pierde. Véalo
Peter Ajtai

24
Realmente no entiendo por qué esta respuesta incluso tiene votos positivos ... especialmente cuando el propio OP acepta que no tiene ningún sentido en algunos comentarios anteriores, ya que podría haberlo hecho var n = 45;.
plalx

72
@scunliffe: Tenga en cuenta que eso new Array(45);no "crea una matriz de 45 elementos" (en el mismo significado que lo [undefined,undefined,..undefined]hace). Más bien "crea una matriz vacía con longitud = 45" ( [undefined x 45]), igual que var foo = []; foo.length=45;. Por eso forEach, y mapno se aplicará en este caso.
tomalec

1310

En ES6 utilizando los métodos Array from () y keys () .

Array.from(Array(10).keys())
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Versión más corta con operador de propagación .

[...Array(10).keys()]
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

75
Solo una nota, esto siempre comenzará en 0. Tendrá que encadenar mapa la matriz para ajustar los valores ( [...Array(10).keys()].map(x => x++);) para comenzar en 1
Sterling Archer

32
Simplemente cambie map(x => x++)a map(x => ++x)debido a que el incremento de precedencia ocurre después del retorno del valor :)
Brock

93
Er qué? ¿Por qué mapcuando puedes simplemente slice? [...Array(N+1).keys()].slice(1)
Robin

19
O no use keysy solo 1 mapa ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn

6060
O no use las teclas y el mapa y simplemente pase una función de mapeo afrom Array.from(Array(10), (e,i)=>i+1)
Fabio Antunes

844

Puedes hacerlo:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

resultado: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

o con valores aleatorios:

Array.apply(null, {length: N}).map(Function.call, Math.random)

resultado: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915954532454

Explicación

Primero, tenga en cuenta que Number.call(undefined, N)es equivalente a Number(N), que simplemente regresa N. Usaremos ese hecho más tarde.

Array.apply(null, [undefined, undefined, undefined])es equivalente a Array(undefined, undefined, undefined), que produce una matriz de tres elementos y se asigna undefineda cada elemento.

¿Cómo puedes generalizar eso a N elementos? Considere cómo Array()funciona, que es algo como esto:

function Array() {
    if ( arguments.length == 1 &&
         'number' === typeof arguments[0] &&
         arguments[0] >= 0 && arguments &&
         arguments[0] < 1 << 32 ) {
        return [  ];  // array of length arguments[0], generated by native code
    }
    var a = [];
    for (var i = 0; i < arguments.length; i++) {
        a.push(arguments[i]);
    }
    return a;
}

Desde ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)también acepta un objeto tipo matriz tipo pato como su segundo parámetro. Si invocamos Array.apply(null, { length: N }), se ejecutará

function Array() {
    var a = [];
    for (var i = 0; i < /* arguments.length = */ N; i++) {
        a.push(/* arguments[i] = */ undefined);
    }
    return a;
}

Ahora tenemos una matriz de elementos N , con cada elemento establecido en undefined. Cuando lo invoquemos .map(callback, thisArg), cada elemento se establecerá en el resultado de callback.call(thisArg, element, index, array). Por [undefined, undefined, …, undefined].map(Number.call, Number)lo tanto, correlacionaría cada elemento con (Number.call).call(Number, undefined, index, array), que es lo mismo Number.call(undefined, index, array)que, como observamos anteriormente, se evalúa como index. Eso completa la matriz cuyos elementos son los mismos que su índice.

¿Por qué pasar por la molestia de en Array.apply(null, {length: N})lugar de solo Array(N)? Después de todo, ambas expresiones resultarían en una matriz de elementos N de elementos indefinidos. La diferencia es que en la primera expresión, cada elemento se establece explícitamente en indefinido, mientras que en la última, cada elemento nunca se estableció. De acuerdo con la documentación de .map():

callbackse invoca solo para índices de la matriz que tienen valores asignados; no se invoca para índices que se han eliminado o a los que nunca se les han asignado valores.

Por lo tanto, Array(N)es insuficiente; Array(N).map(Number.call, Number)resultaría en una matriz sin inicializar de longitud N .

Compatibilidad

Dado que esta técnica se basa en el comportamiento Function.prototype.apply()especificado en ECMAScript 5, no funcionará en navegadores anteriores a ECMAScript 5 como Chrome 14 e Internet Explorer 9.


62
+1 para la inteligencia, pero tenga en cuenta que esto es un orden de magnitud MÁS LENTO que un bucle primitivo: jsperf.com/array-magic-vs-for
warpech

77
Muy inteligente, probablemente también. Explotar el hecho de que Function.prototype.callel primer parámetro es el thisobjeto a mapear directamente sobre Array.prototype.mapel parámetro iterador tiene un cierto brillo.
Noah Freitas

14
Esto es muy, muy inteligente (limita con el abuso de JS). La idea realmente importante aquí es la idiosincrasia de los mapvalores no asignados, en mi opinión. Otra versión (y posiblemente un poco más clara, aunque más larga) es: Array.apply(null, { length: N }).map(function(element, index) { return index; })
Ben Reich el

66
@BenReich Aún mejor (en términos de niveles de abuso de JS): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) o, en el caso de es6 y funciones de flecha, aún más corto: Array.apply(null, new Array(N)).map((_,i) => i)
oddy

1
Si esto devuelve una matriz que comienza en 1, en realidad respondería a la pregunta del OP
Zarzaparrilla

483

Múltiples formas de usar ES6

Usando el operador spread ( ...) y el método de teclas

[ ...Array(N).keys() ].map( i => i+1);

Relleno / Mapa

Array(N).fill().map((_, i) => i+1);

Array.from

Array.from(Array(N), (_, i) => i+1)

Array.from y { length: N }piratear

Array.from({ length: N }, (_, i) => i+1)

Nota sobre forma generalizada

Todas las formas anteriores matrices pueden producir inicializados a los valores casi cualquier deseadas cambiando i+1a la expresión requerida (por ejemplo i*2, -i, 1+i*2, i%2y etc). Si la expresión puede ser expresada por alguna función, fentonces la primera forma se vuelve simplemente

[ ...Array(N).keys() ].map(f)

Ejemplos:

Array.from({length: 5}, (v, k) => k+1); 
// [1,2,3,4,5]

Como la matriz se inicializa con undefinedcada posición, el valor de v seráundefined

Ejemplo mostrando todos los formularios

Ejemplo más genérico con función de inicializador personalizado, fes decir

[ ...Array(N).keys() ].map((i) => f(i))

o incluso más simple

[ ...Array(N).keys() ].map(f)


33
La mejor respuesta en mi humilde opinión. Ver también developer.mozilla.org/de/docs/Web/JavaScript/Reference/…
le_m

55
Use k ++ para matrices que comienzan en 0
Borgboy

1
Si desea incrementar, no use k++, use ++k.
Alex

44
Tenga cuidado con Array.from no es compatible con IE, a menos que lo esté llenando de polietileno
Lauren

2
Para hacer feliz al compilador de TS, considere reemplazar el parámetro no utilizado con lodash: Array.from ({length: 5}, (_, k) => k + 1);
Journeycorner

297

Las matrices administran de manera innata sus longitudes. A medida que se atraviesan, sus índices pueden mantenerse en la memoria y referenciarse en ese punto. Si se necesita conocer un índice aleatorio, indexOfse puede usar el método.


Dicho esto, para sus necesidades, es posible que desee declarar una matriz de cierto tamaño:

var foo = new Array(N);   // where N is a positive integer

/* this will create an array of size, N, primarily for memory allocation, 
   but does not create any defined values

   foo.length                                // size of Array
   foo[ Math.floor(foo.length/2) ] = 'value' // places value in the middle of the array
*/


ES6

Propagar

Al utilizar el operador de propagación ( ...) y el keysmétodo, le permite crear una matriz temporal de tamaño N para producir los índices, y luego una nueva matriz que puede asignarse a su variable:

var foo = [ ...Array(N).keys() ];

Relleno / Mapa

Primero puede crear el tamaño de la matriz que necesita, llenarlo con indefinido y luego crear una nueva matriz usando map, que establece cada elemento en el índice.

var foo = Array(N).fill().map((v,i)=>i);

Array.from

Esto debería inicializarse a una longitud de tamaño N y llenar la matriz en una pasada.

Array.from({ length: N }, (v, i) => i)



En lugar de los comentarios y la confusión, si realmente desea capturar los valores de 1..N en los ejemplos anteriores, hay un par de opciones:

  1. Si el índice está disponible, simplemente puede incrementarlo en uno (por ejemplo, ++i).
  2. en los casos en que no se usa el índice, y posiblemente una forma más eficiente, es crear su matriz pero hacer que N represente N + 1, luego desplazarse hacia adelante.

    Entonces, si deseas 100 números:

    let arr; (arr=[ ...Array(101).keys() ]).shift()





Creo que esto es útil cuando la matriz de números se está utilizando para datos que no se pueden procesar en el extremo receptor. (Como una plantilla HTML que solo está reemplazando valores).
Neil Monroe

Por qué alguien haría esto es tener una matriz de números para llenar una lista desplegable, lo que le da al usuario una opción de 1 a 10. Una pequeña matriz a mano [1,2,3 ... 10] tiene sentido, pero ¿y si es de 1 a 50? ¿Qué pasa si el número final cambia?
CigarDoug

@CigarDoug No dudo que haya un caso de uso, pero supongo que es pequeño. ¿Por qué se necesitaría una matriz de números? Por lo general, al iterar sobre una matriz, se usaría un índice como parte de la construcción del bucle, ya sea como un argumento para la función del cuerpo en bucle o como una variable de contador, por lo que mantener la matriz de números parece trivial solo para crear una matriz de ancho especificado, o simplemente una variable que contiene el límite superior de la matriz. Puedo pensar en algunos casos de uso, pero ninguno de ellos había sido expresado por el OP
vol7ron

44
Como dije, necesito completar un menú desplegable con los números del 1 al 10. Eso es todo. Hay un caso de uso, MI caso de uso. Así es como encontré esta página. Así que construir una matriz a mano fue menos complicado que cualquier cosa que vi aquí. Entonces mis requisitos no son los requisitos del OP. Pero tengo mi respuesta.
CigarDoug

1
@ vol7ron Hay un caso de uso, también tengo uno. En angular, en paginación, quiero mostrar las páginas en el pie de página en las que se puede hacer clic. Entonces hago un bucle de los elementos en una vista con * ngFor = "let p of pagesCounter". ¿Tienes una mejor solución para eso? Por cierto, echa un vistazo a stackoverflow.com/questions/36354325/…
Dalibor

186

En ES6 puedes hacer:

Array(N).fill().map((e,i)=>i+1);

http://jsbin.com/molabiluwa/edit?js,console

Editar: cambiado Array(45)a Array(N)desde que actualizó la pregunta.

console.log(
  Array(45).fill(0).map((e,i)=>i+1)
);


3
+1 porque es una gran O mejor que la .join.splitversión desagradable , pero sigo pensando que el bucle humilde es mejor.
Robin

Estoy de acuerdo @Robin: aparte de la complejidad algorítmica, el humilde bucle siempre es más legible. Sin embargo, con el advenimiento de lambdas en Java, creo mapque pronto se convertirá en un estándar para cosas como esta.
Nate

44
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
Robin

8
No entiendo por qué .fill()es necesario. Veo que es cuando pruebo las respuestas del nodo, pero desde entonces Array(1)[0] === undefined, ¿qué diferencia hace la llamada a fill () Array(1).fill(undefined)?
Dominic

11
Para cualquier otra persona interesada, la diferencia entre Array (N) y Array (N) .fill () se explica bien aquí
Dominic

108

Utilice el método de subrayado muy popular _.range

// _.range([start], stop, [step])

_.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]
_.range(0); // => []


Increíble. Muéstrame un proyecto grande que no use guión bajo de todos modos ...
Erez Cohen

63
function range(start, end) {
    var foo = [];
    for (var i = start; i <= end; i++) {
        foo.push(i);
    }
    return foo;
}

Luego llamado por

var foo = range(1, 5);

No hay una forma integrada de hacer esto en Javascript, pero es una función de utilidad perfectamente válida para crear si necesita hacerlo más de una vez.

Editar: en mi opinión, la siguiente es una mejor función de rango. Quizás solo porque estoy sesgado por LINQ, pero creo que es más útil en más casos. Su experiencia puede ser diferente.

function range(start, count) {
    if(arguments.length == 1) {
        count = start;
        start = 0;
    }

    var foo = [];
    for (var i = 0; i < count; i++) {
        foo.push(start + i);
    }
    return foo;
}

2
Me gusta esto. Si desea hacer un esfuerzo adicional con él, puede declararlo como Array.prototype.range = function (start, end) {...} ;. Luego, puede llamar al rango (x, y) en cualquier objeto Array.
Zach Rattner

8
En lugar de eso, conviértalo en un método en Arraylugar de Array.prototypeque no haya ninguna razón (incluso podría considerarse bastante tonto) para tener este método en cada matriz.
adamse

99
Array.range(1, 5)probablemente sería más apropiado, pero hay algo genial en escribir [].range(1, 5).
MooGoo

"Más bien conviértalo en un método de Array en lugar de Array.prototype" - ¿Cuál es la diferencia? ¿Te refieres solo a una matriz específica?
pilau

3
@pilau Tal como lo dice adamse, se ve raro. Si está en el prototipo, puedes decirlo foo = [1, 2, 3]; bar = foo.range(0, 10);. Pero eso es solo ... confuso. bar = Array.range(0, 10)Es mucho más claro y explícito. El rango no tiene nada que ver con la instancia, por lo que no hay razón para convertirlo en un método de instancia.
Ian Henry

53

La forma más rápida de completar un Arrayv8 es:

[...Array(5)].map((_,i) => i);

el resultado será: [0, 1, 2, 3, 4]


¿hay alguna manera de hacerlo sin la variable adicional _
bluejayke

@bluejayke no :(
аlex dykyі

áspero, ¿sabes cuál es el código fuente de .map? No estoy seguro de si es más rápido que un bucle for, pero si no es así, teóricamente podemos definir la propiedad y hacer una nueva
bluejayke

49

Esta pregunta tiene muchas respuestas complicadas, pero una frase simple:

[...Array(255).keys()].map(x => x + 1)

Además, aunque lo anterior es corto (y ordenado) para escribir, creo que lo siguiente es un poco más rápido (para una longitud máxima de:

127, Int8,

255, Uint8,

32,767, Int16,

65.535, Uint16,

2,147,483,647, Int32,

4.294.967.295, Uint32.

(basado en los valores enteros máximos ), también aquí hay más sobre matrices escritas ):

(new Uint8Array(255)).map(($,i) => i + 1);

Aunque esta solución tampoco es tan ideal, ya que crea dos matrices y usa la declaración de variable adicional "$" (no estoy seguro de ninguna forma de evitar eso usando este método). Creo que la siguiente solución es la forma más rápida posible de hacer esto:

for(var i = 0, arr = new Uint8Array(255); i < arr.length; i++) arr[i] = i + 1;

En cualquier momento después de que se haga esta declaración, puede simplemente usar la variable "arr" en el alcance actual;

Si desea hacer una función simple (con alguna verificación básica):

function range(min, max) {
    min = min && min.constructor == Number ? min : 0;
    !(max && max.constructor == Number && max > min) && // boolean statements can also be used with void return types, like a one-line if statement.
        ((max = min) & (min = 0));  //if there is a "max" argument specified, then first check if its a number and if its graeter than min: if so, stay the same; if not, then consider it as if there is no "max" in the first place, and "max" becomes "min" (and min becomes 0 by default)

    for(var i = 0, arr = new (
        max < 128 ? Int8Array : 
        max < 256 ? Uint8Array :
        max < 32768 ? Int16Array : 
        max < 65536 ? Uint16Array :
        max < 2147483648 ? Int32Array :
        max < 4294967296 ? Uint32Array : 
        Array
    )(max - min); i < arr.length; i++) arr[i] = i + min;
    return arr;
}



//and you can loop through it easily using array methods if you want
range(1,11).forEach(x => console.log(x));

//or if you're used to pythons `for...in` you can do a similar thing with `for...of` if you want the individual values:
for(i of range(2020,2025)) console.log(i);

//or if you really want to use `for..in`, you can, but then you will only be accessing the keys:

for(k in range(25,30)) console.log(k);

console.log(
    range(1,128).constructor.name,
    range(200).constructor.name,
    range(400,900).constructor.name,
    range(33333).constructor.name,
    range(823, 100000).constructor.name,
    range(10,4) // when the "min" argument is greater than the "max", then it just considers it as if there is no "max", and the new max becomes "min", and "min" becomes 0, as if "max" was never even written
);


entonces, con la función anterior, el "one-liner simple" súper lento anterior se convierte en súper rápido, incluso más corto

range(1,14000);

@JVG pero no para la función más rápida?
bluejayke

Exactamente correcto. ¡Es este sencillo revestimiento que todos están buscando!
supersan

@supersan aunque es súper lento :)
bluejayke

JavaScript moderno con el nuevo fillmétodo:Array(255).fill(0,0,255)
cacoder

@cacoder ¿qué tan rápido es, cuántas matrices crea y cuántas iteraciones?
bluejayke

42

Puedes usar esto:

new Array(/*any number which you want*/)
    .join().split(',')
    .map(function(item, index){ return ++index;})

por ejemplo

new Array(10)
    .join().split(',')
    .map(function(item, index){ return ++index;})

creará la siguiente matriz:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Además, ¿por qué no new Array(10).join().split(',').map(function() {return ++arguments[1]});?
Super

1
@Murplyx para algunos casos, la función con argumentos dentro no será optimizada por el motor JS (cierto incluso para V8, vea jsperf.com/arguments-vs-array-argument/2 )
nktssh

44
Esta es una solución interesante, pero es completamente poco práctica: tener que analizar la matriz 3 veces (una vez join, una splitvez y una vez por lo que realmente quieres hacer) simplemente no es agradable: sé que parecen haber caído en desgracia por alguna razón, ¡pero sería mucho mejor simplemente usar un buen bucle antiguo !
Robin

42

ES6 esto hará el truco:

[...Array(12).keys()]

mira el resultado:

[...Array(12).keys()].map(number => console.log(number))


55
en realidad, pidieron 1..N, no 0..N-1
YakovL

1
sí, [...Array(N + 1).keys()].slice(1)rendirá 1..N
David G

Por alguna razón, esta solución no funciona en la versión de producción de la aplicación Expo (react-native). [...Array(N + 1).keys()]este código devuelve una matriz vacía, pero solo en el modo de producción, usando el modo de desarrollo funciona.
FabianoLothor

3
La .keys()respuesta ya se dio hace años y tiene más de 500 votos a favor. ¿Qué le agrega su respuesta?
Dan Dascalescu

39

Si está utilizando d3.js en su aplicación como yo, D3 proporciona una función auxiliar que lo hace por usted.

Entonces, para obtener una matriz de 0 a 4, es tan fácil como:

d3.range(5)
[0, 1, 2, 3, 4]

y para obtener una matriz de 1 a 5, como estaba solicitando:

d3.range(1, 5+1)
[1, 2, 3, 4, 5]

Mira este tutorial para más información.


Este comentario me dio la idea de buscar la función range () en RamdaJS, que resulta ser la biblioteca JS con la que estoy trabajando en mi proyecto actual. Perfecto.
morpático

39

Uso del operador de propagación ES2015 / ES6

[...Array(10)].map((_, i) => i + 1)

console.log([...Array(10)].map((_, i) => i + 1))


77
i + 1tendría más sentido que ++i.
Vincent Cantin

38

Esta es probablemente la forma más rápida de generar una serie de números.

Más corto

var a=[],b=N;while(b--)a[b]=b+1;

En línea

var arr=(function(a,b){while(a--)b[a]=a;return b})(10,[]);
//arr=[0,1,2,3,4,5,6,7,8,9]

Si quieres comenzar desde 1

var arr=(function(a,b){while(a--)b[a]=a+1;return b})(10,[]);
//arr=[1,2,3,4,5,6,7,8,9,10]

¿Quieres una función?

function range(a,b,c){c=[];while(a--)c[a]=a+b;return c}; //length,start,placeholder
var arr=range(10,5);
//arr=[5,6,7,8,9,10,11,12,13,14]

¿POR QUÉ?

  1. while es el bucle más rápido

  2. La configuración directa es más rápida que push

  3. [] es más rápido que new Array(10)

  4. es corto ... mira el primer código. entonces mira todas las otras funciones aquí.

Si te gusta no pueden vivir sin por

for(var a=[],b=7;b>0;a[--b]=b+1); //a=[1,2,3,4,5,6,7]

o

for(var a=[],b=7;b--;a[b]=b+1); //a=[1,2,3,4,5,6,7]

8
Sería mejor respaldar estas afirmaciones con puntos de referencia. Prueba jsperf.com .
Matt Ball

2
lol jsperf ... pls Matt solo porque no te gusta mi respuesta, deja de votar a mis otros ... stackoverflow.com/a/18344296/2450730 ... usa console.time () o cómo se llama ... NO jsperf .
cocco

44
FYI: Como John Reisig publicó por primera vez hace unos años, en algunas plataformas (es decir, windows: P), el tiempo se alimenta al navegador una vez cada 16 ms. También hay otros problemas con la medición del tiempo de ejecución en entornos multitarea. jsperf.com ha implementado la ejecución de las pruebas para que sean estadísticamente correctas. Está bien correr console.time()para tener una intuición, pero para una prueba, necesita jsperf.com Y le muestra los resultados del navegador cruzado de otras personas (hardware diferente, etc.)
naugtur

3
@cocco esto es incorrecto:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav

55
@ cocco, mientras que no siempre es más rápido que otros bucles. En algunos navegadores, una disminución del ciclo while es mucho más lenta que un ciclo for, no puede hacer declaraciones generales sobre el rendimiento de javascript de esa manera porque hay muchas implementaciones con tantas optimizaciones diferentes. Sin embargo, en general, me gusta su enfoque. ;-)
RobG

32

Si está usando lodash, puede usar _.range :

_.range([start=0], end, [step=1])

Crea una serie de números (positivos y / o negativos) que progresan desde el inicio hasta el final, pero sin incluirlos. Se utiliza un paso de -1 si se especifica un inicio negativo sin un final o paso. Si no se especifica end, está configurado para comenzar con start y luego se establece en 0.

Ejemplos:

_.range(4);
// ➜ [0, 1, 2, 3]

_.range(-4);
// ➜ [0, -1, -2, -3]

_.range(1, 5);
// ➜ [1, 2, 3, 4]

_.range(0, 20, 5);
// ➜ [0, 5, 10, 15]

_.range(0, -4, -1);
// ➜ [0, -1, -2, -3]

_.range(1, 4, 0);
// ➜ [1, 1, 1]

_.range(0);
// ➜ []

32

La nueva forma de llenar Arrayes:

const array = [...Array(5).keys()]
console.log(array)

el resultado será: [0, 1, 2, 3, 4]


Esta es una muy buena respuesta, aunque técnicamente la pregunta era de 1-N, no de 0- (N-1)
bluejayke

30

con ES6 puedes hacer:

// `n` is the size you want to initialize your array
// `null` is what the array will be filled with (can be any other value)
Array(n).fill(null)

Dado que los valores de la matriz en realidad están llenos uso de esta solución, mapy forEachtrabajarán.
dontmentionthebackup

27

Informe final resumido .. Drrruummm Rolll -

Este es el código más corto para generar una matriz de tamaño N (aquí 10) sin usar ES6 . La versión anterior de Cocco es cercana pero no la más corta.

(function(n){for(a=[];n--;a[n]=n+1);return a})(10)

Pero el ganador indiscutible de este Golf de código (competencia para resolver un problema particular en la menor cantidad de bytes de código fuente) es Niko Ruotsalainen . Utilizando Array Constructor y ES6 spread operator . (La mayor parte de la sintaxis de ES6 es typeScript válido, pero el siguiente no lo es. Por lo tanto, sea prudente al usarlo)

[...Array(10).keys()]

¿Por qué bajar el voto? Lista larga de respuestas difícil de seguir, así que pensé en resumir.
sapy

¿No es esto 0-10? [... Array (10) .keys ()]
Greg

Webstorm sugiere (nueva matriz (10)). Keys (), ¿es correcto?
Guy

(new Array (10)). keys (), devuelve ArrayIterator {}, no la matriz
sapy

Esto crea una variable global a. El bucle debería serfor(var a=[];n--;a[n]=n+1)
kube el

20

Hay otra forma en ES6, usando Array.from que toma 2 argumentos, el primero es un arrayLike (en este caso un objeto con lengthpropiedad), y el segundo es una función de mapeo (en este caso mapeamos el elemento a su índice)

Array.from({length:10}, (v,i) => i)

esto es más corto y puede usarse para otras secuencias como generar números pares

Array.from({length:10}, (v,i) => i*2)

Además, tiene un mejor rendimiento que la mayoría de las otras formas porque solo se repite una vez a través de la matriz. Verifique el snippit para algunas comparaciones

// open the dev console to see results

count = 100000

console.time("from object")
for (let i = 0; i<count; i++) {
  range = Array.from({length:10}, (v,i) => i )
}
console.timeEnd("from object")

console.time("from keys")
for (let i =0; i<count; i++) {
  range = Array.from(Array(10).keys())
}
console.timeEnd("from keys")

console.time("apply")
for (let i = 0; i<count; i++) {
  range = Array.apply(null, { length: 10 }).map(function(element, index) { return index; })
}
console.timeEnd("apply")


Oye, eso está bien, me gusta. Sin embargo, no devuelve los resultados que OP espera. Para hacer eso, debería escribirse comoArray.from({length:N}, (v,i) => i+1)
CervEd


16

Usando nuevos métodos de matriz y => sintaxis de funciones del estándar ES6 (solo Firefox en el momento de la escritura).

Al llenar agujeros con undefined:

Array(N).fill().map((_, i) => i + 1);

Array.fromconvierte "agujeros" en undefinedtan Array.mapfunciona como se esperaba:

Array.from(Array(5)).map((_, i) => i + 1)

77
Del mismo modo, también se puede hacer lo siguiente en ES6: Array.from({length: N}, (v, k) => k).
XåpplI'-I0llwlg'I -

Se prefiere el enfoque de Xappli: Array.from se creó para casi este escenario exacto, e implica una devolución de llamada de mapeo. Es una excelente solución para el problema general de querer utilizar los métodos de matriz en algo similar a una matriz, sin recurrir a enfoques detallados como Array.prototype.map.call, por ejemplo, para las NodeLists devueltas document.querySelectorAll. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Josh de Qaribou el

Estoy sopesando esto frente a la sintaxis de rango de subrayado, y el rango se lee mejor.
ooolala

Técnicamente, no es lo Array.fromque convierte los valores dispersos en indefinidos. Más bien Array(5)se llama como un objeto de argumentos que a su vez interpreta los valores dispersos como valores indefinidos :)
CervEd

15

Array(...Array(9)).map((_, i) => i);

console.log(Array(...Array(9)).map((_, i) => i))


¡Agradable! También puede escribir esto un poco más sucintamente como[...Array(9)].map((_, i) => i)
Eamonn O'Brien-Strain


12

En ES6:

Array.from({length: 1000}, (_, i) => i);

ES5:

Array.apply(0, {length: 1000}).map(function(x,i){return i});

10

Solo otra versión ES6 .

Al hacer uso del Array.fromsegundo argumento opcional:

Array.from (arrayLike [, mapFn [, thisArg]])

Podemos construir la matriz numerada desde las Array(10)posiciones vacías :

Array.from(Array(10), (_, i) => i)

var arr = Array.from(Array(10), (_, i) => i);
document.write(arr);


Esto es más complicado y ~ 10 veces más lento que [...Array(11).keys()].slice(1).
Dan Dascalescu

10

Parece que el único sabor que no está actualmente en esta lista bastante completa de respuestas es uno con un generador; para remediar eso:

const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]

que puede usarse así:

gen(4) // [0,1,2,3]

Lo bueno de esto es que no solo tienes que aumentar ... Para inspirarte en la respuesta que dio @ igor-shubin, puedes crear una variedad de randoms muy fácilmente:

const gen = N => [...(function*(){let i=0;
  while(i++<N) yield Math.random()
})()]

Y en lugar de algo largo, operacionalmente costoso como:

const slow = N => new Array(N).join().split(',').map((e,i)=>i*5)
// [0,5,10,15,...]

en su lugar podrías hacer:

const fast = N => [...(function*(){let i=0;while(i++<N)yield i*5})()]

10

Puede usar el relleno de matriz y el mapa desde Es6; tal como algunas personas sugirieron en las respuestas que dieron para esta pregunta. A continuación hay algunos ejemplos:

Example-One: Array(10).fill(0).map((e,i)=>i+1)

Result-One: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Example-Two: Array(100/10).fill(0).map((e,i)=>(i*10)+10)

Result-Two:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Prefiero esto porque lo encuentro sencillo y sencillo.



9

Usando ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);

¡Gracias! ¡Esta fue la respuesta más elegante en mi opinión! También se podría usar Array.from(Array(n))si el operador de propagación no es compatible.
Amit

Al principio no sabía por qué tenía que usar el operador de propagación, pero luego leí lo siguiente sobre mapMDN : "No se requieren elementos faltantes de la matriz (es decir, índices que nunca se han establecido, que tienen eliminado o al que nunca se le ha asignado un valor) ".
Battmanz

9

Object.keys(Array.apply(0, Array(3))).map(Number)

Las devoluciones [0, 1, 2]. Muy similar a la excelente respuesta de Igor Shubin , pero con un poco menos de trucos (y un personaje más).

Explicación:

  • Array(3) // [undefined × 3]Genere una matriz de longitud n = 3. Desafortunadamente, esta matriz es casi inútil para nosotros, así que tenemos que ...
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]hacer que la matriz sea iterable. Nota: null es más común que el primer argumento de apply pero 0 es más corto.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] luego obtenga las claves de la matriz (funciona porque las matrices son el tipo de matriz es un objeto con índices para las claves.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] y mapear sobre las teclas, convirtiendo cadenas en números.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.