¿Cuál es la forma más eficiente de crear una matriz arbitraria de longitud cero en JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
¿Cuál es la forma más eficiente de crear una matriz arbitraria de longitud cero en JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
Respuestas:
ES6 presenta Array.prototype.fill
. Se puede usar así:
new Array(len).fill(0);
No estoy seguro si es rápido, pero me gusta porque es breve y se describe a sí mismo.
Todavía no está en IE ( verifique la compatibilidad ), pero hay un polyfill disponible .
new Array(len)
es dolorosamente lento (arr = []).length = len; arr.fill(0);
se trata de la solución más rápida que he visto en cualquier lugar ... o al menos atado
arr = Array(n)
y se (arr = []).length = n
comportan de manera idéntica de acuerdo con las especificaciones. En algunas implementaciones, uno podría ser más rápido, pero no creo que haya una gran diferencia.
(arr = []).length = 1000;
contra la arr = new Array(1000);
velocidad, pruébelo tanto en Chrome como en FF ... new
es terriblemente lento. Ahora, para longitudes de matriz más pequeñas ... digamos <50 o más o menos ... entonces new Array()
parece funcionar mejor. Pero ..
arr.fill(0)
... todo cambia. Ahora, el uso new Array()
es más rápido en la mayoría de los casos, excepto cuando llega a tamaños de matriz> 100000 ... Entonces puede comenzar a ver que la velocidad aumenta nuevamente. Pero si en realidad no tiene que rellenarlo con ceros y puede usar falisy estándar de matrices vacías. Entonces (arr = []).length = x
es una locura rápida en mis casos de prueba la mayor parte del tiempo.
new Array(5).forEach(val => console.log('hi'));
vs new Array(5).fill(undefined).forEach(val => console.log('hi'));
.
Aunque este es un hilo viejo, quería agregarle mis 2 centavos. No estoy seguro de lo lento / rápido que es esto, pero es rápido. Esto es lo que hago:
Si quiero rellenar previamente con un número:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Si quiero rellenar previamente con una cadena:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Otras respuestas han sugerido:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
pero si quieres 0 (el número) y no "0" (cero dentro de una cadena), puedes hacer:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Porque simplemente hacer (nueva matriz (5)). Map (...) no funcionará como dice la especificación
new
) Cuando lo haces Array(5)
, estás creando un objeto que se parece a esto: { length: 5, __proto__: Array.prototype }
- inténtalo console.dir( Array(5) )
. Tenga en cuenta que no tiene ningún propiedades 0
, 1
, 2
, etc, pero cuando apply
que hasta el Array
constructor, que es como decir Array(undefined, undefined, undefined, undefined, undefined)
. Y obtienes un objeto que se parece un poco { length: 5, 0: undefined, 1: undefined...}
. map
funciona en las propiedades 0
, 1
etc., por eso su ejemplo no funciona, pero cuando lo usa apply
sí lo hace.
.apply
es en realidad lo que quieres this
que sea. Para estos fines this
, no importa, solo nos importa realmente la "característica" de difusión de parámetros de .apply
, por lo que puede ser cualquier valor. Me gusta null
porque es barato, probablemente no quieras usarlo {}
o []
porque estarías creando una instancia de un objeto sin ningún motivo.
Aquí hay otra forma de hacerlo usando ES6 que nadie ha mencionado hasta ahora:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
Funciona pasando una función de mapa como el segundo parámetro de Array.from
.
En el ejemplo anterior, el primer parámetro asigna una matriz de 3 posiciones llenas con el valor undefined
y luego la función lambda asigna cada una de ellas al valor 0
.
Aunque Array(len).fill(0)
es más corto, no funciona si necesita completar la matriz haciendo un cálculo primero (sé que la pregunta no lo hizo, pero mucha gente termina buscando esto) .
Por ejemplo, si necesita una matriz con 10 números aleatorios:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
Es más conciso (y elegante) que el equivalente:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
Este método también se puede utilizar para generar secuencias de números aprovechando el parámetro de índice proporcionado en la devolución de llamada:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
Como esta respuesta está recibiendo mucha atención, también quería mostrar este truco genial. Aunque no es tan útil como mi respuesta principal, presentaré el repeat()
método String aún no muy conocido pero muy útil . Aquí está el truco:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
Genial, ¿eh? repeat()
es un método muy útil para crear una cadena que es la repetición de la cadena original un cierto número de veces. Después de eso, split()
crea una matriz para nosotros, que luego es map()
pedida a los valores que queremos. Desglosándolo en pasos:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
truco definitivamente no es deseado en la producción, Array.from()
está perfectamente bien :-)
La solución más rápida
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
La solución más corta (práctica) (3 veces más lenta para matrices pequeñas, ligeramente más lenta para grandes (más lenta en Firefox))
Array(n).fill(0)
Hoy 2020.06.09 realizo pruebas en macOS High Sierra 10.13.6 en los navegadores Chrome 83.0, Firefox 77.0 y Safari 13.1. Pruebo las soluciones elegidas para dos casos de prueba
new Array(n)+for
(N) es la solución más rápida para matrices pequeñas y matrices grandes (excepto Chrome, pero todavía es muy rápida allí) y se recomienda como solución rápida de navegador cruzadonew Float32Array(n)
(I) devuelve una matriz no típica (p. ej., no se puede llamar push(..)
), por lo que no comparo sus resultados con otras soluciones; sin embargo, esta solución es aproximadamente 10-20 veces más rápida que otras soluciones para matrices grandes en todos los navegadoresfor
(L, M, N, O) son rápidas para arreglos pequeñosfill
(B, C) son rápidas en Chrome y Safari pero sorprendentemente más lentas en Firefox para grandes matrices. Son medianamente rápidos para matrices pequeñas.Array.apply
(P) arroja error para grandes matrices
El siguiente código presenta soluciones utilizadas en mediciones
Resultados de ejemplo para Chrome
let a=[]; for(i=n;i--;) a.push(0);
, pero es 4 veces más lento que fill(0)
, por lo que ni siquiera actualizaré la imagen de ese caso.
El método de llenado ES 6 ya mencionado se encarga de esto muy bien. La mayoría de los navegadores de escritorio modernos ya son compatibles con los métodos prototipo de matriz requeridos a partir de hoy (Chromium, FF, Edge y Safari) [ 1 ]. Puede buscar detalles en MDN . Un ejemplo de uso simple es
a = new Array(10).fill(0);
Dado el soporte actual del navegador, debe tener cuidado de usarlo a menos que esté seguro de que su audiencia usa navegadores de escritorio modernos.
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Nota agregada en agosto de 2013, actualizada en febrero de 2015: la respuesta a continuación de 2009 se refiere al Array
tipo genérico de JavaScript . No se relaciona con las matrices tipadas más nuevas definidas en ES2015 [y disponibles ahora en muchos navegadores], me gusta Int32Array
y tal. También tenga en cuenta que ES2015 agrega un fill
método para ambas matrices y matrices con tipo , que es probable que sea la forma más eficiente para llenarlos ...
Además, puede hacer una gran diferencia para algunas implementaciones en la forma de crear la matriz. El motor V8 de Chrome, en particular, intenta usar una matriz de memoria contigua altamente eficiente si cree que puede hacerlo, cambiando a la matriz basada en objetos solo cuando es necesario.
Con la mayoría de los idiomas, sería preasignar, luego rellenar con cero, así:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Pero , las matrices de JavaScript no son realmente matrices , son mapas de clave / valor al igual que todos los demás objetos de JavaScript, por lo que no hay que "preasignar" (establecer la longitud no asigna tantas ranuras para llenar), ni ¿Hay alguna razón para creer que el beneficio de contar regresivamente a cero (que es solo para hacer una comparación rápida en el bucle) no se supera al agregar las claves en orden inverso cuando la implementación puede haber optimizado su manejo de las claves relacionado con las matrices sobre la teoría, generalmente las hará en orden.
De hecho, Matthew Crumley señaló que la cuenta regresiva es notablemente más lenta en Firefox que la cuenta regresiva, un resultado que puedo confirmar: es la parte de la matriz (el bucle descendente a cero es aún más rápido que el bucle hasta un límite en una var). Aparentemente, agregar los elementos a la matriz en orden inverso es una operación lenta en Firefox. De hecho, los resultados varían bastante según la implementación de JavaScript (que no es tan sorprendente). Aquí hay una página de prueba rápida y sucia (a continuación) para las implementaciones del navegador (muy sucia, no rinde durante las pruebas, por lo que proporciona una respuesta mínima y va en contra de los límites de tiempo del script) Recomiendo refrescarse entre pruebas; FF (al menos) se ralentiza en las pruebas repetidas si no lo hace.
La versión bastante complicada que usa Array # concat es más rápida que un init directo en FF a partir de entre 1,000 y 2,000 arreglos de elementos. Sin embargo, en el motor V8 de Chrome, el init directo gana cada vez ...
Aquí está la página de prueba ( copia en vivo ):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
font-weight: bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
'downpre': {
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
'downpost': {
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
'up': {
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
'downandup': {
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
'concat': {
total: 0,
desc: "Concat",
func: makeWithConcat
}
};
document.observe('dom:loaded', function() {
var markup, defname;
markup = "";
for (defname in testdefs) {
markup +=
"<div><input type='checkbox' id='chk_" + defname + "' checked>" +
"<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
}
$('checkboxes').update(markup);
$('btnTest').observe('click', btnTestClick);
});
function epoch() {
return (new Date()).getTime();
}
function btnTestClick() {
// Clear log
$('log').update('Testing...');
// Show running
$('btnTest').disabled = true;
// Run after a pause while the browser updates display
btnTestClickPart2.defer();
}
function btnTestClickPart2() {
try {
runTests();
}
catch (e) {
log("Exception: " + e);
}
// Re-enable the button; we don't yheidl
$('btnTest').disabled = false;
}
function runTests() {
var start, time, counter, length, defname, def, results, a, invalid, lowest, s;
// Get loops and length
s = $F('txtLoops');
runcount = parseInt(s);
if (isNaN(runcount) || runcount <= 0) {
log("Invalid loops value '" + s + "'");
return;
}
s = $F('txtLength');
length = parseInt(s);
if (isNaN(length) || length <= 0) {
log("Invalid length value '" + s + "'");
return;
}
// Clear log
$('log').update('');
// Do it
for (counter = 0; counter <= runcount; ++counter) {
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
start = epoch();
a = def.func(length);
time = epoch() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
invalid = validateResult(a, length);
if (invalid) {
log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
return;
}
}
else {
// Count this one
log("#" + counter + ": " + def.desc + ": " + time + "ms");
def.total += time;
}
}
}
}
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
def.avg = def.total / runcount;
if (typeof lowest != 'number' || lowest > def.avg) {
lowest = def.avg;
}
}
}
results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runcount +
"</p>";
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
}
}
results += "<hr>";
$('log').insert({top: results});
}
function validateResult(a, length) {
var n;
if (a.length != length) {
return "Length is wrong";
}
for (n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
var a;
a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
var a;
a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
var a, i;
a = new Array(len);
for (i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
var a, i;
a = new Array(len);
i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
var a, rem, currlen;
if (len == 0) {
return [];
}
a = [0];
currlen = 1;
while (currlen < len) {
rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
}
else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
$('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>
Por defecto Uint8Array
, Uint16Array
y las Uint32Array
clases mantienen ceros como sus valores, por lo que no necesita ninguna técnica de relleno compleja, simplemente haga lo siguiente:
var ary = new Uint8Array(10);
Todos los elementos de la matriz ary
serán ceros por defecto.
Array.isArray(ary)
es false
. La longitud también es de sólo lectura por lo que no se puede empujar nuevos elementos a ella al igual que conary.push
0
como su valor predeterminado.
Array.from(new Uint8Array(10))
proporcionará una matriz normal.
Array(n).fill(0)
en Chrome si lo que realmente necesita es una matriz JS. Sin embargo, si puede usar un TypedArray, esto es mucho más rápido .fill(0)
, especialmente si puede usar el valor inicializador predeterminado de 0
. No parece haber un constructor que tome un valor de relleno y una longitud, como lo hizo C ++ std::vector
. Parece que para cualquier valor distinto de cero, tiene que construir un TypedArray a cero y luego llenarlo. : /
Si usa ES6, puede usar Array.from () de esta manera:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
Tiene el mismo resultado que
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Porque
Array.from({ length: 3 })
//[undefined, undefined, undefined]
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
Tenga en cuenta que while
es por lo general más eficientes que for-in
, forEach
, etc.
i
extraña la variable local? length
se pasa por valor, por lo que debería poder disminuirlo directamente.
arr[i] = value
). Es mucho más rápido recorrer de principio a fin y usar arr.push(value)
. Es molesto, porque prefiero tu método.
usando notación de objeto
var x = [];
cero lleno? me gusta...
var x = [0,0,0,0,0,0];
lleno de 'indefinido' ...
var x = new Array(7);
notación obj con ceros
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
Como nota al margen, si modifica el prototipo de Array, ambos
var x = new Array();
y
var y = [];
tendrá esas modificaciones prototipo
En cualquier caso, no me preocuparía demasiado la eficiencia o la velocidad de esta operación, hay muchas otras cosas que probablemente harás que son mucho más derrochadoras y costosas que instanciar una variedad de longitud arbitraria que contiene ceros.
null
var x = new Array(7);
new Array(7)
no no crear una matriz "lleno indefinido". Crea una matriz vacía con longitud 7.
(new Array(10)).fill(0)
.
He probado todas las combinaciones de preasignación / no preasignación, conteo ascendente / descendente y bucles for / while en IE 6/7/8, Firefox 3.5, Chrome y Opera.
Las funciones a continuación fueron consistentemente las más rápidas o extremadamente cercanas en Firefox, Chrome e IE8, y no mucho más lentas que las más rápidas en Opera e IE 6. También es la más simple y clara en mi opinión. He encontrado varios navegadores donde la versión del bucle while es un poco más rápida, por lo que también la incluyo como referencia.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
o
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
declaración en la primera parte del bucle for en realidad, separada por solo una coma.
length
valor dado para que no cambie constantemente. Trají una matriz de ceros de 1 millón de longitud de 40ms a 8 en mi máquina.
for (i = 0, array = []; i < length; ++i) array[i] = val;
¿Menos bloques? ... de todos modos, también ... si configuro la array.length
nueva matriz a la longitud ... parece que obtengo otro aumento de velocidad del 10% -15% en FF ... en Chrome, parece duplicar la velocidad -> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(todavía era más rápido si lo dejaba como un for
bucle ... pero el init ya no es necesario, por lo while
que parece ser más rápido en esta versión)
Si necesita crear muchas matrices llenas de cero de diferentes longitudes durante la ejecución de su código, la forma más rápida que he encontrado para lograr esto es crear una matriz cero una vez , usando uno de los métodos mencionados en este tema, de una longitud que sabe que nunca se excederá, y luego corte esa matriz según sea necesario.
Por ejemplo (usando la función de la respuesta elegida arriba para inicializar la matriz), cree una matriz llena de cero de longitud maxLength , como una variable visible para el código que necesita cero matrices:
var zero = newFilledArray(maxLength, 0);
Ahora corte esta matriz cada vez que necesite una matriz llena de ceros de longitud requeridaLongitud < maxLongitud :
zero.slice(0, requiredLength);
Creé miles de arrays llenos miles de veces durante la ejecución de mi código, lo que aceleró enormemente el proceso.
No tengo nada en contra:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
sugerido por Zertosh, pero en una nueva matriz de ES6, las extensiones le permiten hacer esto de forma nativa con el fill
método. Ahora IE edge, Chrome y FF lo admiten, pero consulte la tabla de compatibilidad
new Array(3).fill(0)
le dará [0, 0, 0]
. Puede llenar la matriz con cualquier valor como new Array(5).fill('abc')
(incluso objetos y otras matrices).
Además de eso, puede modificar matrices anteriores con relleno:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
que te da: [1, 2, 3, 9, 9, 6]
La forma en que generalmente lo hago (y es increíblemente rápido) es usar Uint8Array
. Por ejemplo, crear un vector lleno de cero de elementos 1M:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
Soy un usuario de Linux y siempre he trabajado para mí, pero una vez que un amigo que usaba una Mac tenía algunos elementos distintos de cero. Pensé que su máquina no funcionaba bien, pero aún así esta es la forma más segura que encontramos para solucionarlo:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
Editado
Chrome 25.0.1364.160
Firefox 20.0
Falta la prueba más importante (al menos para mí): la Node.js. Sospecho que está cerca del punto de referencia de Chrome.
Usando lodash o guión bajo
_.range(0, length - 1, 0);
O si tiene una matriz existente y desea una matriz de la misma longitud
array.map(_.constant(0));
_.range(0, length, 0)
, creo. Lodash es exclusivo del valor final
A partir de ECMAScript2016 , existe una opción clara para matrices grandes.
Dado que esta respuesta todavía aparece cerca de la parte superior en las búsquedas de Google, aquí hay una respuesta para 2017.
Aquí hay un jsbench actual con algunas docenas de métodos populares, incluidos muchos propuestos hasta ahora sobre esta pregunta. Si encuentra un método mejor, agregue, bifurque y comparta.
Quiero señalar que no existe una forma más eficiente de crear una matriz arbitraria de longitud cero. Puede optimizar la velocidad o la claridad y la facilidad de mantenimiento; puede considerarse la opción más eficiente según las necesidades del proyecto.
Al optimizar la velocidad, desea: crear la matriz usando sintaxis literal; establece la longitud, inicializa la variable iterativa e itera a través de la matriz usando un ciclo while. Aquí hay un ejemplo.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Otra posible implementación sería:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
Pero desaconsejo encarecidamente usar esta segunda implantación en la práctica, ya que es menos clara y no le permite mantener el alcance del bloque en su variable de matriz.
Estos son significativamente más rápidos que el llenado con un bucle for, y aproximadamente un 90% más rápido que el método estándar de
const arr = Array(n).fill(0);
Pero este método de relleno sigue siendo la opción más eficiente para matrices más pequeñas debido a su claridad, concisión y facilidad de mantenimiento. La diferencia de rendimiento probablemente no lo matará a menos que esté haciendo muchos arreglos con longitudes del orden de miles o más.
Algunas otras notas importantes. La mayoría de las guías de estilo recomiendan que ya no se use var
sin una razón muy especial cuando se usa ES6 o posterior. Úselo const
para variables que no se redefinirán y let
para variables que sí lo serán. El MDN y la Guía de estilo de Airbnb son excelentes lugares para obtener más información sobre las mejores prácticas. Las preguntas no se referían a la sintaxis, pero es importante que las personas nuevas en JS conozcan estos nuevos estándares cuando busquen en estas resmas de respuestas antiguas y nuevas.
Para crear una matriz completamente nueva
new Array(arrayLength).fill(0);
Para agregar algunos valores al final de una matriz existente
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
No vi este método en las respuestas, así que aquí está:
"0".repeat( 200 ).split("").map( parseFloat )
Como resultado, obtendrá una matriz de longitud 200 de valor cero:
[ 0, 0, 0, 0, ... 0 ]
No estoy seguro del rendimiento de este código, pero no debería ser un problema si lo usa para arreglos relativamente pequeños.
const arr = Array.from({ length: 10 }).fill(0)
Esta concat
versión es mucho más rápida en mis pruebas en Chrome (2013-03-21). Aproximadamente 200 ms para 10,000,000 elementos vs 675 para init directo.
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
Bonificación: si desea llenar su matriz con cadenas, esta es una forma concisa de hacerlo (no tan rápido como concat
si fuera):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
Estaba probando la gran respuesta de TJ Crowder, y se me ocurrió una fusión recursiva basada en la solución concat que supera a cualquiera de sus pruebas en Chrome (no probé otros navegadores).
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
llama al método con makeRec(29)
.
¿Qué hay de new Array(51).join('0').split('')
?
.map(function(a){return +a})
?
Vale la pena señalar que se Array.prototype.fill
había agregado como parte de la propuesta ECMAScript 6 (Armonía) . Prefiero ir con el polyfill escrito a continuación, antes de considerar otras opciones mencionadas en el hilo.
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
El más corto para el código de bucle
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
Versión var segura
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
, esta sería más corta:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
Mi función más rápida sería:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
Usar el método push y shift nativo para agregar elementos a la matriz es mucho más rápido (aproximadamente 10 veces) que declarar el alcance de la matriz y hacer referencia a cada elemento para establecer su valor.
FYI: constantemente obtengo tiempos más rápidos con el primer ciclo, que es una cuenta regresiva, cuando ejecuto esto en firebug (extensión de firefox).
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
¿Me interesa saber qué hace TJ Crowder con eso? :-)
while (len--)
... tomó mis tiempos de procesamiento de aproximadamente 60 ms a aproximadamente 54 ms
Sabía que tenía este protocolo en alguna parte :)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
Editar: pruebas
En respuesta a Joshua y otros métodos, realicé mi propia evaluación comparativa y estoy viendo resultados completamente diferentes a los reportados.
Esto es lo que probé:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
Resultados:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
Entonces, según mi cálculo, en realidad es más lento en general, pero funciona mejor con matrices más largas en FF pero peor en IE, que en general es una mierda (sorpresa).
b = []...
) es 10-15% más rápido que el primero, pero es más de 10 veces más lento que la respuesta de Joshua.
else {this.length=n;}
después de la this.length
comprobación. Esto acortará una matriz ya existente si es necesario al volver a init
ponerla en una longitud diferente n
.
Función anónima:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Un poco más corto con for-loop:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Funciona con cualquiera Object
, solo cambia lo que hay dentro this.push()
.
Incluso puedes guardar la función:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Llámalo usando:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Agregar elementos a una matriz ya existente:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
Rendimiento: http://jsperf.com/zero-filled-array-creation/25