Quelle est la façon la plus efficace de créer un tableau rempli de longueur arbitraire en JavaScript?
602
Quelle est la façon la plus efficace de créer un tableau rempli de longueur arbitraire en JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
Réponses:
ES6 présente
Array.prototype.fill
. Il peut être utilisé comme ceci:Je ne sais pas si c'est rapide, mais je l'aime parce qu'il est court et auto-descriptif.
Ce n'est toujours pas dans IE ( vérifiez la compatibilité ), mais il existe un polyfill disponible .
la source
new Array(len)
est douloureusement lent.(arr = []).length = len; arr.fill(0);
est la solution la plus rapide que j'aie jamais vue ... ou du moins à égalitéarr = Array(n)
et(arr = []).length = n
se comportent de manière identique selon les spécifications. Dans certaines implémentations, on pourrait être plus rapide, mais je ne pense pas qu'il y ait une grande différence.(arr = []).length = 1000;
contre laarr = new Array(1000);
vitesse, testez-le dans Chrome et FF ...new
c'est terriblement lent. Maintenant, pour des longueurs de tableau plus petites .. disons <50 ou il y a environ ... alorsnew Array()
cela semble mieux fonctionner. Mais ..arr.fill(0)
... tout change en quelque sorte. Maintenant, l'utilisationnew Array()
est plus rapide dans la plupart des cas, sauf lorsque vous atteignez des tailles de tableau> 100 000 ... Ensuite, vous pouvez recommencer à voir l'augmentation de la vitesse. Mais si vous n'avez pas besoin de le pré-remplir avec des zéros et que vous pouvez utiliser une falisy standard de tableaux vides. Ensuite,(arr = []).length = x
c'est fou rapide dans mes cas de test la plupart du temps.new Array(5).forEach(val => console.log('hi'));
vsnew Array(5).fill(undefined).forEach(val => console.log('hi'));
.Bien que ce soit un vieux fil, je voulais y ajouter mes 2 cents. 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:
Si je veux pré-remplir avec une chaîne:
D'autres réponses ont suggéré:
mais si vous voulez 0 (le nombre) et non "0" (zéro dans une chaîne), vous pouvez faire:
la source
Array.apply(null, new Array(5)).map(...)
? Parce que simplement faire (nouveau tableau (5)). Map (...) ne fonctionnera pas comme le dit la spécificationnew
) Quand vous le faites,Array(5)
vous créez un objet qui ressemble un peu à ceci:{ length: 5, __proto__: Array.prototype }
- essayezconsole.dir( Array(5) )
. Notez qu'il n'a pas de propriétés0
,1
,2
, etc. Mais quand vousapply
que jusqu'auArray
constructeur, il est comme direArray(undefined, undefined, undefined, undefined, undefined)
. Et vous obtenez un objet qui ressemble un peu{ length: 5, 0: undefined, 1: undefined...}
.map
fonctionne sur les propriétés0
,1
etc. c'est pourquoi votre exemple ne fonctionne pas, mais quand vous l'utilisezapply
..apply
est en fait ce que vous voulez que cethis
soit. À ces fins, celathis
n'a pas d'importance - nous ne nous soucions vraiment que de la "caractéristique" de répartition des paramètres de.apply
- il peut donc s'agir de n'importe quelle valeur. J'aimenull
parce que c'est bon marché, vous ne voulez probablement pas l'utiliser{}
ou[]
puisque vous instancieriez un objet sans raison.Manière élégante de remplir un tableau avec des valeurs précalculées
Voici une autre façon de le faire en utilisant ES6 que personne n'a mentionné jusqu'à présent:
Il fonctionne en passant une fonction de carte comme deuxième paramètre de
Array.from
.Dans l'exemple ci-dessus, le premier paramètre alloue un tableau de 3 positions remplies avec la valeur
undefined
, puis la fonction lambda mappe chacun d'eux à la valeur0
.Bien que ce
Array(len).fill(0)
soit plus court, cela ne fonctionne pas si vous devez remplir le tableau en faisant d'abord du calcul (je sais que la question ne l'a pas demandé, mais beaucoup de gens se retrouvent ici à le chercher) .Par exemple, si vous avez besoin d'un tableau avec 10 nombres aléatoires:
C'est plus concis (et élégant) que l'équivalent:
Cette méthode peut également être utilisée pour générer des séquences de nombres en tirant parti du paramètre d'index fourni dans le rappel:
Réponse bonus: remplir un tableau à l'aide de String
repeat()
Étant donné que cette réponse reçoit beaucoup d'attention, je voulais également montrer ce truc cool. Bien que pas aussi utile que ma réponse principale, présentera la
repeat()
méthode String encore peu connue, mais très utile . Voici l'astuce: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 ensuitemap()
suivi des valeurs que nous voulons. Décomposer en plusieurs étapes:la source
repeat
astuce ne soit certainement pas recherchée en production, elleArray.from()
est parfaitement bien :-)En bref
Solution la plus rapide
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Solution la plus courte (pratique) (3 fois plus lente pour les petites baies, légèrement plus lente pour les grandes (la plus lente sur Firefox))
Array(n).fill(0)
Détails
Aujourd'hui 2020.06.09, j'effectue des tests sur macOS High Sierra 10.13.6 sur les navigateurs Chrome 83.0, Firefox 77.0 et Safari 13.1. Je teste les solutions choisies pour deux cas de test
Conclusions
new Array(n)+for
(N) est la solution la plus rapide pour les petites baies et les grandes baies (sauf Chrome mais toujours très rapide là-bas) et elle est recommandée comme solution multi-navigateur rapidenew Float32Array(n)
(I) renvoie un tableau non typique (par exemple, vous ne pouvez pas l'appelerpush(..)
) donc je ne compare pas ses résultats avec d'autres solutions - cependant cette solution est environ 10-20x plus rapide que les autres solutions pour les grands tableaux sur tous les navigateursfor
(L, M, N, O) sont rapides pour les petits tableauxfill
(B, C) sont rapides sur Chrome et Safari mais étonnamment plus lentes sur Firefox pour les grands tableaux. Ils sont moyennement rapides pour les petits tableauxArray.apply
(P) génère une erreur pour les grands tableauxAfficher l'extrait de code
Code et exemple
Le code ci-dessous présente les solutions utilisées dans les mesures
Afficher l'extrait de code
Exemple de résultats pour Chrome
la source
let a=[]; for(i=n;i--;) a.push(0);
- mais il est 4 fois plus lent quefill(0)
- donc je ne mettrai même pas à jour l'image avec ce cas.La méthode de remplissage ES 6 déjà mentionnée s'en occupe bien. La plupart des navigateurs de bureau modernes prennent déjà en charge les méthodes de prototype de baie requises à ce jour (Chromium, FF, Edge et Safari) [ 1 ]. Vous pouvez rechercher des détails sur MDN . Un exemple d'utilisation simple est
Compte tenu de la prise en charge actuelle du navigateur, vous devez être prudent si vous n'êtes pas sûr que votre public utilise des navigateurs de bureau modernes.
la source
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Note ajoutée août 2013, mise à jour février 2015: La réponse ci-dessous de 2009 concerne le
Array
type générique de JavaScript . Il ne concerne pas les plus récents typés tableaux définis dans ES2015 [et disponible maintenant dans de nombreux navigateurs], commeInt32Array
et autres. Notez également que ES2015 ajoute unefill
méthode aux tableaux et aux tableaux typés , ce qui est probablement le moyen le plus efficace de les remplir ...En outre, cela peut faire une grande différence pour certaines implémentations dans la façon dont vous créez le tableau. Le moteur V8 de Chrome, en particulier, essaie d'utiliser un tableau de mémoire contiguë très efficace s'il le pense, en ne basculant sur le tableau basé sur les objets que lorsque cela est nécessaire.
Avec la plupart des langues, il s'agirait d'une pré-allocation, puis d'un remplissage nul, comme ceci:
Mais , les tableaux JavaScript ne sont pas vraiment des tableaux , ce sont des cartes clé / valeur comme tous les autres objets JavaScript, donc il n'y a pas de "pré-allocation" à faire (la définition de la longueur n'alloue pas autant d'emplacements à remplir), ni y a-t-il une raison de croire que l'avantage du compte à rebours à zéro (qui est juste de rendre la comparaison rapide dans la boucle) n'est pas contrebalancé par l'ajout des clés dans l'ordre inverse alors que la mise en œuvre pourrait bien avoir optimisé leur gestion des clés liés aux tableaux sur la théorie, vous les ferez généralement dans l'ordre.
En fait, Matthew Crumley a souligné que le décompte est nettement plus lent sur Firefox que le décompte, un résultat que je peux confirmer - c'est la partie du tableau (le bouclage jusqu'à zéro est toujours plus rapide que le bouclage jusqu'à une limite dans une var). 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 beaucoup selon l'implémentation de JavaScript (ce qui n'est pas si 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 minimal et ne respectera pas les limites de temps du 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 init direct sur FF entre 1 000 et 2 000 tableaux d'éléments. Cependant, sur le moteur V8 de Chrome, l'initialisation droite l'emporte à chaque fois ...
Voici la page de test ( copie en direct ):
la source
Par défaut
Uint8Array
,Uint16Array
et lesUint32Array
classes conservent les zéros comme valeurs, vous n'avez donc pas besoin de techniques de remplissage complexes, faites simplement:tous les éléments du tableau
ary
seront des zéros par défaut.la source
Array.isArray(ary)
estfalse
. La longueur est également en lecture seule, vous ne pouvez donc pas y insérer de nouveaux éléments comme avecary.push
0
leur valeur par défaut.Array.from(new Uint8Array(10))
fournira un tableau normal.Array(n).fill(0)
dans Chrome si ce dont vous avez vraiment besoin est un tableau JS. Si vous pouvez utiliser un TypedArray, cela est même beaucoup plus rapide que.fill(0)
, surtout si vous pouvez utiliser la valeur d'initialisation par défaut de0
. Il ne semble pas y avoir de constructeur qui accepte une valeur de remplissage et une longueur, comme le fait C ++std::vector
. Il semble que pour toute valeur non nulle, vous devez construire un TypedArray mis à zéro, puis le remplir. : /Si vous utilisez ES6, vous pouvez utiliser Array.from () comme ceci:
A le même résultat que
Parce que
la source
Notez que
while
est généralement plus efficace quefor-in
,forEach
etc.la source
i
variable locale n'est-elle pas étrangère?length
est passé par valeur, vous devriez donc pouvoir le décrémenter directement.arr[i] = value
). Il est beaucoup plus rapide de parcourir du début à la fin et de l'utiliserarr.push(value)
. C'est ennuyeux, car je préfère ta méthode.en utilisant la notation d'objet
zéro rempli? comme...
rempli de 'indéfini' ...
notation obj avec des zéros
En remarque, si vous modifiez le prototype d'Array, les deux
et
aura ces modifications de prototype
En tout cas, je ne serais pas trop préoccupé par l'efficacité ou la vitesse de cette opération, il y a beaucoup d'autres choses que vous ferez probablement qui sont beaucoup plus inutiles et coûteuses que l'instanciation d'un tableau de longueur arbitraire contenant des zéros.
la source
null
s dans ce tableau -var x = new Array(7);
new Array(7)
ne crée pas un tableau "rempli de non défini". Il crée un tableau vide de longueur 7.(new Array(10)).fill(0)
.J'ai testé toutes les combinaisons de boucles de pré-allocation / non pré-allocation, de comptage / décroissement et pour / pendant 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 lentes que les plus rapides dans Opera et IE 6. C'est aussi la plus simple et la plus claire à mon avis. J'ai trouvé plusieurs navigateurs où la version de la boucle while est légèrement plus rapide, donc je l'inclus aussi pour référence.
ou
la source
var array = []
déclaration dans la première partie de la boucle for, séparée par une virgule uniquement.length
valeur déjà donnée afin qu'il ne change pas constamment. Apporté un tableau de 1 million de longueur de zéro de 40 ms à 8 sur ma machine.for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Moins de blocs? ... de toute façon, aussi ... si je règle laarray.length
longueur du nouveau tableau .. il me semble que j'obtiens une autre augmentation de vitesse de 10% à 15% dans FF ... dans Chrome, il semble doubler la vitesse ->var i, array = []; array.length = length; while(i < length) array[i++] = val;
(était encore plus rapide si jefor
lewhile
laissais en boucle ... mais l'init n'est plus nécessaire, donc c'est apparemment plus rapide sur cette version)Si vous devez créer de nombreux tableaux remplis de zéro de longueurs différentes pendant l'exécution de votre code, le moyen le plus rapide que j'ai trouvé pour y parvenir est de créer une fois un tableau zéro , en utilisant l'une des méthodes mentionnées sur ce sujet, d'une longueur que vous savez ne sera jamais dépassé, puis découpez ce tableau si nécessaire.
Par exemple (en utilisant la fonction de la réponse choisie ci-dessus pour initialiser le tableau), créez un tableau rempli de zéro de longueur maxLength , comme une variable visible par le code qui a besoin de zéro tableaux:
Tranchez maintenant ce tableau à chaque fois que vous avez besoin d'un tableau rempli de zéro de longueur requiredLength < maxLength :
Je créais des tableaux remplis de zéro des milliers de fois pendant l'exécution de mon code, ce qui a considérablement accéléré le processus.
la source
la source
new Array(size+1).join("x").split("x").map(function() { return 0; })
pour obtenir des chiffres réelsnew Array(size+1).join('0').split('').map(Number)
Je n'ai rien contre:
suggéré par Zertosh, mais dans un nouveau tableau ES6 , les extensions vous permettent de le faire en natif avec la
fill
méthode. 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 commenew Array(5).fill('abc')
(même des objets et d'autres tableaux).En plus de cela, vous pouvez modifier les tableaux précédents avec fill:
ce qui vous donne:
[1, 2, 3, 9, 9, 6]
la source
La façon dont je le fais habituellement (et c'est incroyablement rapide) utilise
Uint8Array
. Par exemple, créer un vecteur rempli de zéro d'éléments 1M:Je suis un utilisateur Linux et j'ai toujours travaillé pour moi, mais une fois qu'un ami utilisant un Mac avait des éléments différents de zéro. Je pensais que sa machine fonctionnait mal, mais voici toujours le moyen le plus sûr que nous avons trouvé pour le réparer:
Édité
Chrome 25.0.1364.160
Firefox 20.0
Il manque le test le plus important (du moins pour moi): celui de Node.js. Je le soupçonne proche du benchmark Chrome.
la source
Utiliser lodash ou underscore
Ou si vous avez un tableau existant et que vous voulez un tableau de la même longueur
la source
_.range(0, length, 0)
, je crois. Lodash est exclusif de la valeurSolution ES6:
la source
Depuis ECMAScript2016 , il y a un choix clair pour les grands tableaux.
Étant donné que cette réponse apparaît toujours en haut sur les recherches Google, voici une réponse pour 2017.
Voici un jsbench actuel 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, bifurquer et partager.
Je veux noter qu'il n'y a pas de véritable moyen le plus efficace de créer un tableau rempli de longueur arbitraire. Vous pouvez optimiser la vitesse ou la clarté et la maintenabilité - l'un ou l'autre peut être considéré comme le choix le plus efficace en fonction des besoins du projet.
Lors de l'optimisation de la vitesse, vous souhaitez: créer le tableau à l'aide de la syntaxe littérale; définissez la longueur, initialisez la variable d'itération et parcourez le tableau à l'aide d'une boucle while. Voici un exemple.
Une autre mise en œuvre possible serait:
Mais je déconseille fortement d'utiliser cette deuxième implantation dans la pratique car elle est moins claire et ne vous permet pas de maintenir la portée du bloc sur votre variable de 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
Mais cette méthode de remplissage reste le choix le plus efficace pour les petits tableaux en raison de sa clarté, de sa concision et de sa maintenabilité. La différence de performances ne vous tuera probablement pas à moins que vous ne fabriquiez beaucoup de tableaux avec des longueurs de l'ordre de milliers ou plus.
Quelques autres notes importantes. La plupart des guides de style vous recommandent de ne plus utiliser
var
sans raison très spéciale lors de l'utilisation d'ES6 ou d'une version ultérieure. À utiliserconst
pour les variables qui ne seront pas redéfinies etlet
pour les variables qui le seront. Le MDN et le Airbnb's Style Guide sont d'excellents endroits où aller pour plus d'informations sur les meilleures pratiques. Les questions ne portaient pas sur la syntaxe, mais il est important que les nouveaux utilisateurs de JS connaissent ces nouvelles normes lorsqu'ils recherchent parmi ces rames d'anciennes et de nouvelles réponses.la source
Pour créer un tout nouveau tableau
Pour ajouter des valeurs à la fin d'un tableau existant
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
Exemple
la source
Je n'ai pas vu cette méthode dans les réponses, alors voici:
En conséquence, vous obtiendrez un tableau de valeur nulle de longueur 200:
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.
la source
la source
Cette
concat
version est beaucoup plus rapide dans mes tests sur Chrome (2013-03-21). Environ 200 ms pour 10 000 000 d'éléments contre 675 pour une init droite.Bonus: si vous voulez remplir votre tableau avec des chaînes, c'est une façon concise de le faire (pas aussi vite que
concat
si):la source
Je testais la grande réponse de TJ Crowder, et j'ai proposé une fusion récursive basée sur la solution concat qui surpasse n'importe laquelle dans ses tests dans Chrome (je n'ai pas testé d'autres navigateurs).
appelez la méthode avec
makeRec(29)
.la source
Et alors
new Array(51).join('0').split('')
?la source
.map(function(a){return +a})
?Il convient peut-être de le signaler, qui
Array.prototype.fill
avait été ajouté dans le cadre de la proposition ECMAScript 6 (Harmony) . Je préfère aller avec le polyfill écrit ci-dessous, avant d'envisager d'autres options mentionnées sur le fil.la source
Le plus court pour le code de boucle
Version var sûre
la source
n
, elle serait plus courte:for(var a=[];n--;a[n]=0);
la source
Ma fonction la plus rapide serait:
L'utilisation du push and shift natif pour ajouter des éléments au tableau est beaucoup plus rapide (environ 10 fois) que de déclarer la portée du tableau et de référencer chaque élément pour définir sa valeur.
fyi: J'obtiens constamment des temps plus rapides avec la première boucle, qui compte à rebours, lorsque je l'exécute dans firebug (extension firefox).
J'aimerais savoir ce que TJ Crowder en fait? :-)
la source
while (len--)
.. a pris mes temps de traitement d'environJe savais que j'avais ce proto quelque part :)
Edit: tests
En réponse à Joshua et à d'autres méthodes, j'ai effectué mon propre benchmarking et je vois des résultats complètement différents de ceux rapportés.
Voici ce que j'ai testé:
Résultats:
Donc, à mon avis, la poussée est en effet plus lente en général, mais fonctionne mieux avec des tableaux plus longs dans FF mais pire dans IE, ce qui est nul en général (quelle surprise).
la source
b = []...
) est 10 à 15% plus rapide que la première, mais elle est plus de 10 fois plus lente que la réponse de Joshua.else {this.length=n;}
après lathis.length
-check. Cela raccourcira un tableau déjà existant si nécessaire lors de sainit
recialisation à une longueur différenten
.Fonction anonyme:
Un peu plus court avec for-loop:
Fonctionne avec tout
Object
, changez simplement ce qu'il y a à l'intérieurthis.push()
.Vous pouvez même enregistrer la fonction:
Appelez-le en utilisant:
Ajout d'éléments à un tableau déjà existant:
Performances: http://jsperf.com/zero-filled-array-creation/25
la source