Quel est le moyen le plus efficace de créer un tableau rempli de zéro de longueur arbitraire en JavaScript?
ES6 introduit Array.prototype.fill
. Il peut être utilisé comme ceci:
_new Array(len).fill(0);
_
Je ne sais pas si c'est rapide, mais j'aime bien parce que c'est court et qu'il se décrit lui-même.
Ce n'est toujours pas dans IE ( vérification de la compatibilité ), mais il y a un polyfill disponible .
Bien que ce soit un vieux fil, je voulais y ajouter mes 2 centimes. Je ne sais pas à quel point c'est lent/rapide, mais c'est une doublure rapide. Voici ce que je fais:
Si je veux pré-remplir un numéro:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Si je veux pré-remplir avec une chaîne:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
D'autres réponses ont suggéré:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
mais si vous voulez 0 (le nombre) et pas "0" (zéro dans une chaîne), vous pouvez faire:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Voici une autre façon de le faire en utilisant ES6 que personne n’a encore mentionnée:
_> Array.from(Array(3), () => 0)
< [0, 0, 0]
_
Cela fonctionne en passant une fonction de carte comme second paramètre de Array.from
.
Dans l'exemple ci-dessus, le premier paramètre alloue un tableau de 3 positions remplies de la valeur undefined
, puis la fonction lambda mappe chacune d'elles à la valeur _0
_.
Bien que Array(len).fill(0)
soit plus court, cela ne fonctionne pas si vous devez remplir le tableau en effectuant d'abord un calcul (je sais que la question ne vous l'a pas demandé, mais beaucoup des gens finissent ici à la recherche de cela) .
Par exemple, si vous avez besoin d'un tableau avec 10 nombres aléatoires:
_> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
_
C'est plus concis (et élégant) que l'équivalent:
_const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
_
Cette méthode peut également être utilisée pour générer des séquences de nombres en tirant parti du paramètre index fourni dans le rappel:
_> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_
repeat()
Comme cette réponse suscite beaucoup d'attention, je voulais aussi montrer ce truc sympa. Bien que pas aussi utile que ma réponse principale, introduira la méthode encore peu connue, mais très utile String repeat()
. Voici le truc:
_> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
_
Cool hein? repeat()
est une méthode très utile pour créer une chaîne qui est la répétition de la chaîne d'origine un certain nombre de fois. Après cela, split()
crée un tableau pour nous, qui est ensuite map()
ped aux valeurs que nous voulons. Décomposant par étapes:
_> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
_
La méthode de remplissage ES 6 déjà mentionnée s’occupe bien de cela. La plupart des navigateurs de bureau modernes prennent déjà en charge les méthodes de prototype Array requises à l’heure actuelle (Chrome, FF, Edge et Safari) [ 1 ]. Vous pouvez rechercher des détails sur MDN . Un exemple d'utilisation simple est
a = new Array(10).fill(0);
Compte tenu de la prise en charge actuelle du navigateur, vous devez faire preuve de prudence si vous n'utilisez pas les navigateurs modernes.
Note ajoutée en août 2013, mise à jour en février 2015: la réponse ci-dessous à partir de 2009 concerne le type générique Array
de JavaScript. Il ne concerne pas les nouveaux tableaux typés définis dans ES2015 [et disponibles maintenant dans de nombreux navigateurs], comme Int32Array
et ainsi de suite. Notez également que ES2015 ajoute une méthode fill
à la fois Tableaux et tableaux typés , ce qui est probablement le moyen le plus efficace de les remplir ...
De plus, la manière dont vous créez le tableau peut avoir un impact considérable sur certaines implémentations. Le moteur V8 de Chrome, en particulier, essaie d'utiliser un tableau hautement efficace à mémoire contiguë s'il le pense, en passant au tableau à base d'objet uniquement lorsque cela est nécessaire .
Avec la plupart des langues, ce serait pré-allouer, puis remplir de zéro, comme ceci:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Mais, tableaux JavaScript ne sont pas vraiment des tableaux , ce sont des cartes clé/valeur, comme tous les autres objets JavaScript. Il n'y a donc pas de "pré-allocation" à faire (réglage la longueur n'alloue pas autant de créneaux à combler), et il n'y a aucune raison de penser que l'avantage de décompter à zéro (ce qui est juste pour faire la comparaison dans la boucle rapidement) n'est pas compensé par l'ajout des clés ordre inverse lorsque la mise en œuvre a peut-être optimisé le traitement des clés liées aux tableaux sur la théorie, vous les effectuerez généralement dans l’ordre.
En fait, Matthew Crumley a souligné que le compte à rebours est nettement plus lent sous Firefox que le compte à rebours, résultat que je peux confirmer: il en fait partie du tableau (la mise en boucle à zéro est toujours plus rapide que la boucle allant jusqu'à une limite dans une variable). Apparemment, l'ajout des éléments au tableau dans l'ordre inverse est une opération lente sur Firefox. En fait, les résultats varient un peu selon l’implémentation de JavaScript (ce qui n’est pas surprenant). Voici une page de test rapide et sale (ci-dessous) pour les implémentations de navigateur (très sale, ne cède pas pendant les tests, fournit donc un retour d'informations minimal et dépasse le délai de script). Je recommande de rafraîchir entre les tests; FF (au moins) ralentit les tests répétés si vous ne le faites pas.
La version assez compliquée qui utilise Array # concat est plus rapide qu’un simple init sur FF à partir de 1.000 à 2.000 éléments. Sur le moteur V8 de Chrome, cependant, les initiales gagnent à chaque fois ...
Voici la page de test ( live copy ):
<!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>
Array(n).fill(0)
(16 caractères), où n
est la taille du tableau
2018.10.28, j'ai comparé les performances de 15 propositions d'autres réponses. Les tests ont été effectués sur Mac OS X 10.13.6 High Sierra, sur trois navigateurs: Chrome 69.0.3497, Safari 12.0 (13606.2.11) et Firefox 63.0 (64 bits).
Ci-dessous, je présente les résultats pour le navigateur le plus rapide (safari):
Pour tous les navigateurs, la solution la plus rapide était M - mais ce n’est pas un "tableau typique" (mais très rapide) - Safari 33.8k opérations/seconde, Chrome 5,2k, 3,5k FF,
Les solutions les plus rapides pour les tableaux classiques:
La solution la plus lente:
Solution N ne fonctionne que sur Firefox et Chrome.
Le plus rapide:
Le plus lent:
n
sur Firefox) était Mlet a = new Float32Array(n)
(mais ce n'est pas un tableau typique). Pour cette raison, le navigateur le plus rapide était Safari ( pour les gros n
> 6 fois plus vite que Chrome,> 9 fois plus vite que firefox)let a = Array(n).fill(0)
(code rapide et code court)Vous pouvez effectuer des tests sur votre machine ici .
Par défaut, les classes Uint8Array
, Uint16Array
et Uint32Array
conservent les zéros comme valeurs. Vous n'avez donc pas besoin de techniques de remplissage complexes.
var ary = new Uint8Array(10);
tous les éléments du tableau ary
seront des zéros par défaut.
Si vous utilisez ES6, vous pouvez utiliser Array.from () comme ceci:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
A le même résultat que
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Parce que
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']
Notez que while
est généralement plus efficace que for-in
, forEach
, etc.
J'ai testé toutes les combinaisons de boucles pré-allouées/non pré-allouées, comptées haut/bas et pendant/tant dans IE 6/7/8, Firefox 3.5, Chrome et Opera.
Les fonctions ci-dessous étaient systématiquement les plus rapides ou extrêmement proches dans Firefox, Chrome et IE8, et pas beaucoup plus lentement que les plus rapides dans Opera et IE 6. C'est également le plus simple et le plus clair dans mon avis. J'ai trouvé plusieurs navigateurs où la version de la boucle while est légèrement plus rapide, je l'inclue donc aussi pour référence.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
ou
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
en utilisant la notation objet
var x = [];
rempli de zéro? comme...
var x = [0,0,0,0,0,0];
rempli de 'indéfini' ...
var x = new Array(7);
notation obj avec zéros
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
En remarque, si vous modifiez le prototype de Array, les deux
var x = new Array();
et
var y = [];
aura ces modifications de prototype
En tout état de cause, je ne me soucierais pas trop de l’efficacité ou de la rapidité de cette opération; vous ferez probablement beaucoup de choses beaucoup plus coûteuses et coûteuses que d’instaurer une série de longueurs arbitraires contenant des zéros.
function zeroFilledArray(size) {
return new Array(size + 1).join('0').split('');
}
Si vous devez créer plusieurs tableaux remplis de zéros de différentes longueurs lors de l'exécution de votre code, le moyen le plus rapide que j'ai trouvé pour y parvenir est de créer un tableau zéro ne fois, en utilisant l'une des méthodes mentionnées sur ce sujet, d’une longueur que vous savez ne sera jamais dépassée, puis coupez ce tableau en fonction des besoins.
Par exemple (en utilisant la fonction de la réponse choisie ci-dessus pour initialiser le tableau), créez un tableau rempli de zéros de longueur maxLength , sous forme de variable visible par le code qui n'a pas besoin de tableaux:
var zero = newFilledArray(maxLength, 0);
Découpez maintenant ce tableau à chaque fois que vous avez besoin d’un tableau rempli de zéros requiredLength < maxLength :
zero.slice(0, requiredLength);
Je créais des tableaux remplis de zéros des milliers de fois lors de l'exécution de mon code, ce qui a considérablement accéléré le processus.
Je n'ai rien contre:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
suggéré par Zertosh, mais dans une nouvelle ES6 les extensions de tableau vous permettent de le faire de manière native avec la méthode fill
. Maintenant, IE Edge, Chrome et FF le prennent en charge, mais vérifiez le tableau de compatibilité
new Array(3).fill(0)
vous donnera [0, 0, 0]
. Vous pouvez remplir le tableau avec n'importe quelle valeur comme new Array(5).fill('abc')
(même les objets et autres tableaux).
En plus de cela, vous pouvez modifier les tableaux précédents avec remplissage:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
qui vous donne: [1, 2, 3, 9, 9, 6]
La façon dont je le fais habituellement (et qui est très rapide) utilise Uint8Array
. Par exemple, créant un vecteur rempli à zéro d'éléments 1M:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
Je suis un utilisateur de Linux et j'ai toujours travaillé pour moi, mais un ami utilisant un Mac avait déjà des éléments non nuls. Je pensais que sa machine fonctionnait mal, mais voici le moyen le plus sûr que nous ayons trouvé pour le réparer:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
édité
Chrome 25.0.1364.160
Firefox 20.0
Manquant le test le plus important (du moins pour moi): celui de Node.js. Je le soupçonne de s'approcher de Chrome.
[...new Array(5)].map(x => 0); // [0, 0, 0, 0, 0]
À partir de ECMAScript2016 , il existe un choix clair pour les tableaux de grande taille.
Étant donné que cette réponse figure toujours parmi les meilleures dans les recherches sur Google, voici une réponse pour 2017.
Voici une version courante jsbench avec quelques dizaines de méthodes populaires, dont beaucoup ont été proposées jusqu'à présent sur cette question. Si vous trouvez une meilleure méthode, veuillez ajouter, fourchette et partager.
Je tiens à noter qu’il n’existe aucun moyen vraiment efficace de créer un tableau rempli de zéro de longueur arbitraire. Vous pouvez optimiser la vitesse, la clarté et la facilité de maintenance. Vous pouvez soit considérer le choix le plus efficace en fonction des besoins du projet.
Lorsque vous optimisez la vitesse, vous souhaitez: créer le tableau en utilisant une syntaxe littérale; définissez la longueur, initialisez la variable itérative et parcourez le tableau à l'aide d'une boucle while. Voici un exemple.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Une autre implémentation possible serait:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
Mais je déconseille fortement l’utilisation de cette seconde implantation dans la pratique car elle est moins claire et ne vous permet pas de maintenir la portée du bloc sur la variable de votre tableau.
Celles-ci sont nettement plus rapides que le remplissage avec une boucle for, et environ 90% plus rapides que la méthode standard de
const arr = Array(n).fill(0);
Mais cette méthode de remplissage reste le choix le plus efficace pour les baies plus petites en raison de sa clarté, de sa concision et de sa facilité de maintenance. La différence de performances ne vous tuera probablement pas, sauf si vous faites beaucoup de tableaux avec des longueurs de l'ordre de milliers ou plus.
Quelques autres notes importantes. La plupart des guides de style recommandent de ne plus utiliser var
sans raison particulière lorsque vous utilisez ES6 ou une version ultérieure. Utilisez const
pour les variables qui ne seront pas redéfinies et let
pour les variables qui le seront. Les MDN et Le Guide de la style de Airbnb sont d'excellents endroits où aller pour obtenir plus d'informations sur les meilleures pratiques. Les questions ne portaient pas sur la syntaxe, mais il est important que les débutants en JS connaissent ces nouvelles normes lors de la recherche parmi ces innombrables réponses anciennes et nouvelles.
Utiliser lodash ou trait de soulignement
_.range(0, length - 1, 0);
Ou si vous avez un tableau existant et que vous voulez un tableau de la même longueur
array.map(_.constant(0));
Je n'ai pas vu cette méthode dans les réponses, alors la voici:
"0".repeat( 200 ).split("").map( parseFloat )
En résultat, vous obtiendrez un tableau de longueur zéro de 200:
[ 0, 0, 0, 0, ... 0 ]
Je ne suis pas sûr des performances de ce code, mais cela ne devrait pas être un problème si vous l'utilisez pour des tableaux relativement petits.
Qu'en est-il de new Array(51).join('0').split('')
?
Ma fonction la plus rapide serait:
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
L'utilisation de la méthode native Push and shift pour ajouter des éléments au tableau est beaucoup plus rapide (environ 10 fois) que de déclarer l'étendue du tableau et de référencer chaque élément pour en définir la valeur.
fyi: J'obtiens régulièrement des temps plus rapides avec la première boucle, qui compte à rebours, lorsque je lance ceci dans firebug (extension 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
Je suis intéressé de savoir ce que T.J. Crowder en fait? :-)
Je testais la bonne réponse de T.J. Crowder, et est venu avec une fusion récursive basée sur la solution de concat qui surpasse tous ses tests dans Chrome (je n'ai pas testé d'autres navigateurs).
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;
},
appelez la méthode avec makeRec(29)
.
Cette version de concat
est beaucoup plus rapide lors de mes tests sur Chrome (2013-03-21). Environ 200 ms pour 10 000 000 d’éléments contre 675 pour les initiales.
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: si vous voulez remplir votre tableau avec des chaînes, c’est une façon concise de le faire (mais pas aussi vite que concat
bien que):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
Le plus court pour code de boucle
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;
Version sécurisée var
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
Pour créer un nouveau tablea
new Array(arrayLength).fill(0);
Pour ajouter des valeurs à la fin d'un tableau existant
[...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)]);
Je savais que j'avais proto'd quelque part :)
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);
Edit: tests
En réponse à Joshua et à d’autres méthodes, j’ai effectué ma propre analyse comparative et j’observe des résultats complètement différents de ceux rapportés.
Voici ce que j'ai testé:
//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();
Résultats:
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
Donc, à mon avis, Push est généralement plus lent, mais fonctionne mieux avec des tableaux plus longs en FF, mais plus mauvais en IE, ce qui est vraiment nul (en général, quelle surprise).
Il peut être intéressant de noter que Array.prototype.fill
a été ajouté dans le cadre de la proposition ECMAScript 6 (Harmony) . Je préférerais utiliser le polyfill écrit ci-dessous, avant d’envisager d’autres options mentionnées sur le fil.
_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;
};
}
_
var str = "0000000...0000";
var arr = str.split("");
utilisation dans les expressions: arr[i]*1;
EDIT: si arr
est supposé être utilisé dans des expressions entières, ne vous inquiétez pas de la valeur de caractère '0'. Vous l'utilisez simplement comme suit: a = a * arr[i]
(en supposant que a
a une valeur entière).
Je viens d'utiliser:
var arr = [10];
for (var i=0; i<=arr.length;arr[i] = i, i++);
Fonction anonyme:
(function(n) { while(n-- && this.Push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Un peu plus court avec for-loop:
(function(n) { for(;n--;this.Push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Fonctionne avec n'importe quel Object
, il suffit de changer le contenu de this.Push()
.
Vous pouvez même enregistrer la fonction:
function fill(size, content) {
for(;size--;this.Push(content));
return this;
}
Appelez-le en utilisant:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Ajouter des éléments à un tableau déjà existant:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
Performance: http://jsperf.com/zero-filled-array-creation/25
Ce qui manque à tout le monde, c’est de régler au préalable longueur du tableau afin que l’interprète ne change pas constamment la taille du tableau.
Mon simple one-liner serait Array.prototype.slice.apply(new Uint8Array(length))
Mais si je devais créer une fonction pour le faire rapidement sans contourner le problème, j’écrirais probablement une fonction comme celle-ci:
var filledArray = function(value, l) {
var i = 0, a = []; a.length = l;
while(i<l) a[i++] = value;
return a;
}
Comme noté par plusieurs autres, utiliser .concat()
fournit généralement des solutions rapides. Voici une solution récursive simple:
function zeroFill(len, a){
return len <= (a || (a = [0])).length ?
a.slice(0, len) :
zeroFill(len, a.concat(a))
}
console.log(zeroFill(5));
Et une fonction de remplissage de tableau récursif à usage général:
function fill(len, v){
return len <= (v = [].concat(v, v)).length ?
v.slice(0, len) : fill(len, v)
}
console.log(fill(5, 'abc'));
Vous pouvez vérifier si l'index existe ou non, afin d'y ajouter +1.
ainsi, vous n’avez pas besoin d’un tableau rempli de zéros.
EXEMPLE:
var current_year = new Date().getFullYear();
var ages_array = new Array();
for (var i in data) {
if(data[i]['BirthDate'] != null && data[i]['BirthDate'] != '0000-00-00'){
var birth = new Date(data[i]['BirthDate']);
var birth_year = birth.getFullYear();
var age = current_year - birth_year;
if(ages_array[age] == null){
ages_array[age] = 1;
}else{
ages_array[age] += 1;
}
}
}
console.log(ages_array);
Il y a toujours la solution phpjs, que vous pouvez trouver ici:
http://phpjs.org/functions/array_fill/
Je ne peux pas parler pour le projet (créer une bibliothèque de fonctions javascript qui reflète la plus grande fonctionnalité de php) dans son ensemble, mais les quelques fonctions que j'ai personnellement tirées ont fonctionné comme un champion.
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
Le moyen le plus rapide de le faire est avec forEach =)
(nous conservons la compatibilité descendante pour IE <9)
var fillArray = Array.prototype.forEach
? function(arr, n) {
arr.forEach(function(_, index) { arr[index] = n; });
return arr;
}
: function(arr, n) {
var len = arr.length;
arr.length = 0;
while(len--) arr.Push(n);
return arr;
};
// test
fillArray([1,2,3], 'X'); // => ['X', 'X', 'X']
Une autre option de Nice trouvée ici http://www.2ality.com/2013/11/initializing-arrays.html
function fillArrayWithNumbers(n) {
var arr = Array.apply(null, Array(n));
return arr.map(function (x, i) { return i });
}