Was ist der effizienteste Weg, um ein Array mit beliebiger Länge und Null in JavaScript zu erstellen?
let i = 0; Array.from(Array(10), ()=>i++);
Was ist der effizienteste Weg, um ein Array mit beliebiger Länge und Null in JavaScript zu erstellen?
let i = 0; Array.from(Array(10), ()=>i++);
Antworten:
ES6 stellt vor Array.prototype.fill
. Es kann folgendermaßen verwendet werden:
new Array(len).fill(0);
Ich bin mir nicht sicher, ob es schnell ist, aber ich mag es, weil es kurz und selbstbeschreibend ist.
Es ist immer noch nicht im IE ( Kompatibilität prüfen ), aber es ist eine Polyfüllung verfügbar .
new Array(len)
ist schmerzhaft langsam. (arr = []).length = len; arr.fill(0);
ist ungefähr die schnellste Lösung, die ich jemals gesehen habe ... oder zumindest gebunden
arr = Array(n)
und (arr = []).length = n
verhalten sich entsprechend der Spezifikation identisch. In einigen Implementierungen könnte man schneller sein, aber ich glaube nicht, dass es einen großen Unterschied gibt.
(arr = []).length = 1000;
gegen arr = new Array(1000);
Geschwindigkeitstest in Chrome und FF ... das new
ist furchtbar langsam. Nun, für Array-Längen kleiner ... sagen wir <50 oder so ungefähr ... dann new Array()
scheint es besser zu funktionieren. Aber ..
arr.fill(0)
... ändert sich alles irgendwie. Jetzt ist die Verwendung new Array()
in den meisten Fällen schneller, außer wenn Sie Arraygrößen> 100000 erreichen ... Dann können Sie beginnen, die Geschwindigkeitssteigerung wieder zu sehen. Aber wenn Sie es nicht mit Nullen vorfüllen müssen und Standard-Falisy von leeren Arrays verwenden können. Dann (arr = []).length = x
ist in meinen Testfällen die meiste Zeit verrückt schnell.
new Array(5).forEach(val => console.log('hi'));
vs new Array(5).fill(undefined).forEach(val => console.log('hi'));
.
Obwohl dies ein alter Thread ist, wollte ich meine 2 Cent hinzufügen. Ich bin mir nicht sicher, wie langsam / schnell das ist, aber es ist ein schneller Einzeiler. Folgendes mache ich:
Wenn ich eine Nummer vorab ausfüllen möchte:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Wenn ich mit einer Zeichenfolge vorfüllen möchte:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Andere Antworten haben vorgeschlagen:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
Wenn Sie jedoch 0 (die Zahl) und nicht "0" (Null innerhalb einer Zeichenfolge) möchten, können Sie Folgendes tun:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Weil einfach zu tun (neues Array (5)). Map (...) nicht funktioniert, wie die Spezifikation sagt
new
) Wenn Sie dies tun Array(5)
, erstellen Sie ein Objekt, das irgendwie so aussieht: { length: 5, __proto__: Array.prototype }
- versuchen Sie es console.dir( Array(5) )
. Beachten Sie, dass es keine Eigenschaften hat 0
,1
, 2
etc. Aber wenn man , apply
dass zu dem Array
Konstruktor, es ist wie wenn man sagt Array(undefined, undefined, undefined, undefined, undefined)
. Und du bekommst ein Objekt, das irgendwie aussieht { length: 5, 0: undefined, 1: undefined...}
. map
arbeitet auf die Eigenschaften 0
, 1
etc. weshalb Ihr Beispiel nicht funktioniert, aber wenn Sie apply
es tut.
.apply
ist eigentlich das, was Sie wollen this
. Für diese Zwecke spielt das this
keine Rolle - wir kümmern uns nur wirklich um die Parameter-Spreizfunktion von .apply
- also kann es ein beliebiger Wert sein. Ich mag es, null
weil es billig ist, Sie es wahrscheinlich nicht verwenden möchten {}
oder []
weil Sie ein Objekt ohne Grund instanziieren würden.
Hier ist eine andere Möglichkeit, ES6 zu verwenden, die bisher noch niemand erwähnt hat:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
Es funktioniert durch Übergeben einer Kartenfunktion als zweiten Parameter von Array.from
.
Im obigen Beispiel weist der erste Parameter ein Array von 3 Positionen zu, die mit dem Wert gefüllt sind, undefined
und dann ordnet die Lambda-Funktion jede dieser Positionen dem Wert zu0
.
Obwohl Array(len).fill(0)
es kürzer ist, funktioniert es nicht, wenn Sie das Array zuerst mit Berechnungen füllen müssen (ich weiß, dass die Frage nicht danach gefragt hat, aber viele Leute suchen hier danach). .
Wenn Sie beispielsweise ein Array mit 10 Zufallszahlen benötigen:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
Es ist prägnanter (und eleganter) als das Äquivalent:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
Diese Methode kann auch verwendet werden, um Zahlenfolgen zu generieren, indem der im Rückruf angegebene Indexparameter genutzt wird:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
Da diese Antwort viel Aufmerksamkeit erhält, wollte ich auch diesen coolen Trick zeigen. Obwohl nicht so nützlich wie meine Hauptantwort, wird der noch nicht sehr bekannte, aber sehr nützliche String vorgestelltrepeat()
Methode eingeführt. Hier ist der Trick:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
Cool was? repeat()
ist eine sehr nützliche Methode, um eine Zeichenfolge zu erstellen, bei der die ursprüngliche Zeichenfolge eine bestimmte Anzahl von Malen wiederholt wird. Danach split()
erstellt er ein Array für uns, das dann map()
auf die gewünschten Werte eingestellt wird. Aufteilung in Schritte:
> "?".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
Trick in der Produktion definitiv nicht erwünscht ist, Array.from()
ist er vollkommen in Ordnung :-)
Schnellste Lösung
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Kürzeste (handliche) Lösung (3x langsamer für kleine Arrays, etwas langsamer für große (am langsamsten bei Firefox))
Array(n).fill(0)
Heute 2020.06.09 führe ich Tests unter macOS High Sierra 10.13.6 in den Browsern Chrome 83.0, Firefox 77.0 und Safari 13.1 durch. Ich teste ausgewählte Lösungen für zwei Testfälle
new Array(n)+for
(N) ist die schnellste Lösung für kleine und große Arrays (außer Chrome, aber immer noch sehr schnell) und wird als schnelle browserübergreifende Lösung empfohlennew Float32Array(n)
(I) basierende Lösung gibt ein nicht typisches Array zurück (z. B. können Sie nicht aufrufenpush(..)
), sodass ich die Ergebnisse nicht mit anderen Lösungen vergleiche. Diese Lösung ist jedoch etwa 10 bis 20 Mal schneller als andere Lösungen für große Arrays in allen Browsernfor
(L, M, N, O) basieren, sind für kleine Arrays schnellfill
(B, C) , sind in Chrome und Safari schnell, in Firefox für große Arrays jedoch überraschend langsam. Sie sind mittelschnell für kleine ArraysArray.apply
(P) basierende Lösung löst einen Fehler für große Arrays aus
Der folgende Code enthält Lösungen für Messungen
Beispielergebnisse für Chrome
let a=[]; for(i=n;i--;) a.push(0);
- aber es ist 4x langsamer als fill(0)
- also werde ich das Bild in diesem Fall nicht einmal aktualisieren.
Die bereits erwähnte ES 6-Füllmethode sorgt dafür. Die meisten modernen Desktop-Browser unterstützen bereits heute die erforderlichen Array-Prototyp-Methoden (Chromium, FF, Edge und Safari) [ 1 ]. Sie können Details zu MDN nachschlagen . Ein einfaches Anwendungsbeispiel ist
a = new Array(10).fill(0);
Angesichts der aktuellen Browserunterstützung sollten Sie vorsichtig sein, es sei denn, Sie sind sicher, dass Ihre Zielgruppe moderne Desktop-Browser verwendet.
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Hinweis hinzugefügt August 2013, aktualisiert Februar 2015: Die folgende Antwort aus dem Jahr 2009 bezieht sich auf den generischen Array
Typ von JavaScript . Es bezieht sich nicht auf die neueren typisierten Arrays, die in ES2015 definiert sind [und jetzt in vielen Browsern verfügbar sind], wie Int32Array
und so. Beachten Sie auch, dass ES2015 fill
sowohl Arrays als auch typisierten Arrays eine Methode hinzufügt , die wahrscheinlich die effizienteste Methode ist, um sie zu füllen ...
Außerdem kann es bei einigen Implementierungen einen großen Unterschied machen, wie Sie das Array erstellen. Insbesondere die V8-Engine von Chrome versucht, ein hocheffizientes Array mit zusammenhängendem Speicher zu verwenden, wenn sie dies für möglich hält, und wechselt nur bei Bedarf zum objektbasierten Array.
Bei den meisten Sprachen wird es vorab zugewiesen und dann wie folgt mit Null gefüllt:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Aber , JavaScript - Arrays sind nicht wirklich Arrays , sie sind Schlüssel / Wert - Karten wie alle anderen JavaScript - Objekte, so gibt es keine „vorbelegt“ zu tun (Einstellung der Länge zuteilen nicht , dass viele Slots zu füllen), noch Gibt es einen Grund zu der Annahme, dass der Vorteil des Herunterzählens auf Null (der nur dazu dient, den Vergleich in der Schleife schnell zu machen) nicht durch das Hinzufügen der Schlüssel in umgekehrter Reihenfolge aufgewogen wird, wenn die Implementierung möglicherweise die Handhabung der Schlüssel optimiert hat Bezogen auf Arrays in der Theorie werden Sie sie im Allgemeinen in der richtigen Reihenfolge ausführen.
Tatsächlich wies Matthew Crumley darauf hin, dass das Herunterzählen in Firefox deutlich langsamer ist als das Hochzählen, ein Ergebnis, das ich bestätigen kann - es ist der Array-Teil davon (das Schleifen auf Null ist immer noch schneller als das Schleifen bis zu einem Grenzwert in einer Var). Anscheinend ist das Hinzufügen der Elemente zum Array in umgekehrter Reihenfolge eine langsame Operation in Firefox. Tatsächlich variieren die Ergebnisse je nach JavaScript-Implementierung erheblich (was nicht allzu überraschend ist). Hier ist eine schnelle und schmutzige Testseite (unten) für Browser-Implementierungen (sehr schmutzig, gibt während der Tests nicht nach, bietet daher nur minimales Feedback und läuft unter Einhaltung der Skript-Zeitlimits). Ich empfehle, zwischen den Tests zu aktualisieren. FF verlangsamt sich (zumindest) bei wiederholten Tests, wenn Sie dies nicht tun.
Die ziemlich komplizierte Version, die Array # concat verwendet, ist schneller als ein Straight Init auf FF, und zwar zwischen 1.000 und 2.000 Elementarrays. Bei der V8-Engine von Chrome gewinnt Straight Init jedoch jedes Mal ...
Hier ist die Testseite ( Live-Kopie ):
<!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>
In der Standardeinstellung Uint8Array
, Uint16Array
und Uint32Array
Klassen halten Nullen als Werte, so dass Sie keine komplexen Abfülltechniken benötigen, gerade tun:
var ary = new Uint8Array(10);
Alle Elemente des Arrays ary
sind standardmäßig Nullen.
Array.isArray(ary)
ist false
. Die Länge ist auch schreibgeschützt, so dass Sie keine neuen Elemente wie beiary.push
0
ihren Standardwert bei.
Array.from(new Uint8Array(10))
stellt ein normales Array bereit.
Array(n).fill(0)
in Chrome, wenn Sie wirklich ein JS-Array benötigen. Wenn Sie ein TypedArray verwenden können, ist dies sogar viel schneller als .fill(0)
, insbesondere wenn Sie den Standardinitialisiererwert von verwenden können 0
. Es scheint keinen Konstruktor zu geben, der einen Füllwert und eine Länge annimmt, wie es C ++ getan std::vector
hat. Es scheint, dass Sie für jeden Wert ungleich Null ein typisiertes Array mit Null erstellen und es dann füllen müssen. : /
Wenn Sie ES6 verwenden, können Sie Array.from () wie folgt verwenden :
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
Hat das gleiche Ergebnis wie
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
weil
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']
Beachten Sie, dass while
in der Regel effizienter als ist for-in
, forEach
usw.
i
lokale Variable nicht irrelevant? length
wird als Wert übergeben, sodass Sie ihn direkt dekrementieren können sollten.
arr[i] = value
. B. ). Es ist viel schneller, von Anfang bis Ende durchzugehen und zu verwenden arr.push(value)
. Es ist ärgerlich, weil ich Ihre Methode bevorzuge.
mit Objektnotation
var x = [];
Null gefüllt? mögen...
var x = [0,0,0,0,0,0];
gefüllt mit 'undefiniert' ...
var x = new Array(7);
Objektnotation mit Nullen
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
Nebenbei bemerkt, wenn Sie den Prototyp von Array ändern, beides
var x = new Array();
und
var y = [];
wird diese Prototyp-Modifikationen haben
Auf jeden Fall würde ich mich nicht allzu sehr um die Effizienz oder Geschwindigkeit dieses Vorgangs kümmern. Es gibt viele andere Dinge, die Sie wahrscheinlich tun werden, die weitaus verschwenderischer und teurer sind, als ein Array beliebiger Länge mit Nullen zu instanziieren.
null
s in diesem Array -var x = new Array(7);
new Array(7)
ist nicht ein Array „gefüllt mit undefinierten“ erstellen. Es erstellt ein leeres Array mit der Länge 7.
(new Array(10)).fill(0)
.
Ich habe in IE 6/7/8, Firefox 3.5, Chrome und Opera alle Kombinationen von Vorzuweisung / Nichtvorzuweisung, Aufwärts- / Abwärts- und For / While-Schleifen getestet.
Die folgenden Funktionen waren in Firefox, Chrome und IE8 durchweg die schnellsten oder extremsten und in Opera und IE 6 nicht viel langsamer als die schnellsten. Sie sind meiner Meinung nach auch die einfachsten und klarsten. Ich habe mehrere Browser gefunden, in denen die while-Schleifenversion etwas schneller ist, daher füge ich sie auch als Referenz hinzu.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
oder
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
Deklaration auch in den ersten Teil der for-Schleife werfen, der nur durch ein Komma getrennt ist.
length
bereits angegebenen Wert ein, damit es sich nicht ständig ändert. Brachte ein 1 Million langes Array von Nullen von 40 ms bis 8 auf meinen Computer.
for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Weniger Blöcke? ... jedenfalls auch ... wenn ich array.length
das neue Array auf die Länge setze ... ich bekomme eine weitere Geschwindigkeitssteigerung von 10% -15% in FF ... in Chrome scheint es die Geschwindigkeit zu verdoppeln -> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(war immer noch schneller, wenn ich es als for
Schleife belassen habe ... aber der Init wird nicht mehr benötigt, so dass der while
bei dieser Version scheinbar schneller ist)
Wenn Sie während der Ausführung Ihres Codes viele mit Nullen gefüllte Arrays unterschiedlicher Länge erstellen müssen, besteht der schnellste Weg, dies zu erreichen, darin, einmal mit einer der in diesem Thema genannten Methoden ein Null-Array mit einer Länge zu erstellen von denen Sie wissen, dass sie niemals überschritten werden, und schneiden Sie das Array dann nach Bedarf auf.
Erstellen Sie beispielsweise (unter Verwendung der Funktion aus der oben gewählten Antwort zum Initialisieren des Arrays) ein mit Null gefülltes Array mit der Länge maxLength als Variable, die für den Code sichtbar ist, der Null-Arrays benötigt:
var zero = newFilledArray(maxLength, 0);
Schneiden Sie dieses Array jetzt jedes Mal in Scheiben, wenn Sie ein mit Null gefülltes Array mit der erforderlichen Länge benötigen. Länge < maxLänge :
zero.slice(0, requiredLength);
Ich habe während der Ausführung meines Codes tausende Male null gefüllte Arrays erstellt, was den Prozess enorm beschleunigte.
Ich habe nichts gegen:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
Von Zertosh vorgeschlagen, aber in einer neuen ES6- Array-Erweiterung können Sie dies nativ mit der fill
Methode tun . Jetzt unterstützen IE Edge, Chrome und FF dies, überprüfen Sie jedoch die Kompatibilitätstabelle
new Array(3).fill(0)
werde dir geben [0, 0, 0]
. Sie können das Array mit einem beliebigen Wert wie new Array(5).fill('abc')
(auch Objekten und anderen Arrays) füllen .
Darüber hinaus können Sie vorherige Arrays mit fill ändern:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
was dir gibt: [1, 2, 3, 9, 9, 6]
Die Art und Weise, wie ich es normalerweise mache (und es ist erstaunlich schnell), ist die Verwendung Uint8Array
. Beispiel: Erstellen eines mit Nullen gefüllten Vektors aus 1 Millionen Elementen:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
Ich bin ein Linux-Benutzer und habe immer für mich gearbeitet, aber einmal hatte ein Freund, der einen Mac verwendete, einige Elemente ungleich Null. Ich dachte, seine Maschine funktioniert nicht richtig, aber hier ist der sicherste Weg, dies zu beheben:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
Bearbeitet
Chrome 25.0.1364.160
Firefox 20.0
Ich vermisse den wichtigsten Test (zumindest für mich): den Node.js. Ich vermute, dass es nahe am Chrome-Benchmark liegt.
Mit lodash oder Unterstrich
_.range(0, length - 1, 0);
Oder wenn ein Array vorhanden ist und Sie ein Array mit derselben Länge möchten
array.map(_.constant(0));
_.range(0, length, 0)
, glaube ich. Lodash ist exklusiv vom Endwert
Ab ECMAScript2016 gibt es eine klare Wahl für große Arrays.
Da diese Antwort bei Google-Suchanfragen immer noch ganz oben angezeigt wird, finden Sie hier eine Antwort für 2017.
Hier ist eine aktuelle jsbench mit ein paar Dutzend gängigen Methoden, darunter viele, die bisher zu dieser Frage vorgeschlagen wurden. Wenn Sie eine bessere Methode finden, fügen Sie diese bitte hinzu, teilen Sie sie und teilen Sie sie.
Ich möchte darauf hinweisen, dass es keinen wirklich effizientesten Weg gibt, ein Array mit beliebiger Länge und Null zu erstellen. Sie können die Geschwindigkeit oder die Klarheit und Wartbarkeit optimieren - je nach den Anforderungen des Projekts kann entweder die effizientere Wahl getroffen werden.
Bei der Optimierung der Geschwindigkeit möchten Sie: das Array mithilfe der Literal-Syntax erstellen; Legen Sie die Länge fest, initialisieren Sie die iterierende Variable und durchlaufen Sie das Array mithilfe einer while-Schleife. Hier ist ein Beispiel.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Eine andere mögliche Implementierung wäre:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
Ich rate jedoch dringend davon ab, diese zweite Implantation in der Praxis zu verwenden, da sie weniger klar ist und es Ihnen nicht ermöglicht, das Block-Scoping für Ihre Array-Variable beizubehalten.
Diese sind deutlich schneller als das Füllen mit einer for-Schleife und etwa 90% schneller als die Standardmethode von
const arr = Array(n).fill(0);
Diese Füllmethode ist jedoch aufgrund ihrer Klarheit, Prägnanz und Wartbarkeit immer noch die effizienteste Wahl für kleinere Arrays. Der Leistungsunterschied wird Sie wahrscheinlich nicht töten, wenn Sie nicht viele Arrays mit Längen in der Größenordnung von Tausenden oder mehr erstellen.
Ein paar andere wichtige Hinweise. Die meisten Styleguides empfehlen, dass Sie var
ES6 oder höher nicht ohne besonderen Grund mehr verwenden . Verwendung const
für Variablen, die nicht neu definiert werden, und let
für Variablen, die neu definiert werden. Das MDN und der Airbnb Style Guide sind großartige Orte, um weitere Informationen zu Best Practices zu erhalten. Bei den Fragen ging es nicht um Syntax, aber es ist wichtig, dass JS-Neulinge diese neuen Standards kennen, wenn sie diese Unmengen alter und neuer Antworten durchsuchen.
So erstellen Sie ein völlig neues Array
new Array(arrayLength).fill(0);
Hinzufügen einiger Werte am Ende eines vorhandenen Arrays
[...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)]);
Ich habe diese Methode nicht in Antworten gesehen, also hier ist sie:
"0".repeat( 200 ).split("").map( parseFloat )
Als Ergebnis erhalten Sie ein nullwertiges Array mit einer Länge von 200:
[ 0, 0, 0, 0, ... 0 ]
Ich bin mir über die Leistung dieses Codes nicht sicher, aber es sollte kein Problem sein, wenn Sie ihn für relativ kleine Arrays verwenden.
const arr = Array.from({ length: 10 }).fill(0)
Diese concat
Version ist in meinen Tests auf Chrome (21.03.2013) viel schneller. Etwa 200 ms für 10.000.000 Elemente gegenüber 675 für Straight Init.
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));
}
Bonus: Wenn Sie Ihr Array mit Strings füllen möchten, ist dies eine kurze Möglichkeit (nicht ganz so schnell wie concat
):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
Ich habe die großartige Antwort von TJ Crowder getestet und eine rekursive Zusammenführung gefunden, die auf der Concat-Lösung basiert, die alle seine Tests in Chrome übertrifft (ich habe keine anderen Browser getestet).
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;
},
Rufen Sie die Methode mit auf makeRec(29)
.
Es könnte erwähnenswert sein, dass Array.prototype.fill
dies als Teil des ECMAScript 6 (Harmony) -Vorschlags hinzugefügt wurde . Ich würde mich lieber für die unten beschriebene Polyfüllung entscheiden, bevor ich andere im Thread erwähnte Optionen in Betracht ziehe.
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;
};
}
Am kürzesten für Schleifencode
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;
Sichere var-Version
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
, wäre diese kürzer:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
Meine schnellste Funktion wäre:
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
Das native Drücken und Verschieben zum Hinzufügen von Elementen zum Array ist viel schneller (ungefähr zehnmal) als das Deklarieren des Array-Bereichs und das Referenzieren jedes Elements, um seinen Wert festzulegen.
fyi: Ich bekomme durchweg schnellere Zeiten mit der ersten Schleife, die herunterzählt, wenn ich diese in Firebug (Firefox-Erweiterung) ausführe.
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
Ich bin interessiert zu wissen, was TJ Crowder daraus macht. :-)
while (len--)
... ändern . Ich habe meine Verarbeitungszeiten von ungefähr 60 ms auf ungefähr 54
Ich wusste, dass ich dieses Proto irgendwo hatte :)
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);
Bearbeiten: Tests
Als Reaktion auf Joshua und andere Methoden habe ich mein eigenes Benchmarking durchgeführt und sehe völlig andere Ergebnisse als die gemeldeten.
Folgendes habe ich getestet:
//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();
Ergebnisse:
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
Meiner Meinung nach ist Push zwar im Allgemeinen langsamer, schneidet aber bei längeren Arrays in FF besser ab, im IE jedoch schlechter, was im Allgemeinen nur zum Kotzen ist (Quel-Überraschung).
b = []...
) ist 10-15% schneller als die erste, aber mehr als zehnmal langsamer als Joshuas Antwort.
else {this.length=n;}
nach dem this.length
Check ein. Dadurch wird ein bereits vorhandenes Array bei Bedarf verkürzt, wenn init
es auf eine andere Länge neu initialisiert wird n
.
Anonyme Funktion:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Etwas kürzer mit for-Schleife:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Funktioniert mit jedem Object
, ändern Sie einfach, was drin ist this.push()
.
Sie können die Funktion sogar speichern:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Nennen Sie es mit:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Hinzufügen von Elementen zu einem bereits vorhandenen Array:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']