Comment créer un tableau contenant 1… N

1163

Je recherche des alternatives à la ci-dessous pour créer un tableau JavaScript contenant 1 à N où N n'est connu qu'au moment de l'exécution.

var foo = [];

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

Pour moi, il semble qu'il devrait y avoir un moyen de le faire sans la boucle.

Godders
la source
224
Après avoir lu toute cette page, je suis arrivé à la conclusion que votre propre boucle for simple est la plus simple, la plus lisible et la moins sujette aux erreurs.
Kokodoko
Si quelqu'un a besoin de quelque chose de plus avancé, j'ai créé une bibliothèque node.js qui le fait pour les chiffres, les lettres, les plages négatives / positives, etc. github.com/jonschlinkert/fill-range . Il est utilisé dans github.com/jonschlinkert/braces pour l'expansion des accolades et github.com/jonschlinkert/micromatch pour les modèles glob
jonschlinkert
1
Vous devriez éditer pour dire "Comment créer un tableau de longueur N" au lieu de "... contenant 1 ... N", ce dernier implique qu'il y aura des éléments avec des valeurs de 1 à N
Steven Landow
7
@StevenLandow pourquoi OP devrait-il être renommé? Il veut un tableau avec des valeurs 1 ... N?
Andre Elrico
Bonne question, bon titre, réponses (un peu) idiotes.
Bitterblue

Réponses:

381

Si j'obtiens ce que vous recherchez, vous voulez un tableau de chiffres 1..nque vous pourrez ensuite parcourir.

Si c'est tout ce dont vous avez besoin, pouvez-vous le faire à la place?

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

puis quand vous voulez l'utiliser ... (non optimisé, juste par exemple)

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

Par exemple, si vous n'avez pas besoin de stocker quoi que ce soit dans le tableau, vous avez juste besoin d'un conteneur de la bonne longueur sur lequel vous pouvez itérer ... cela pourrait être plus facile.

Voyez-le en action ici: http://jsfiddle.net/3kcvm/

scunliffe
la source
4
impressionné que vous ayez réussi à formuler ma question mieux que moi, vous avez en effet raison car à la réflexion, tout ce dont j'ai besoin est un tableau de chiffres que je pourrai parcourir plus tard :) Merci pour votre réponse.
Godders
147
@Godders: Si c'est ce que vous cherchez, pourquoi avez-vous besoin d'un tableau? Un simple var n = 45;puis bouclage 1..nferait l'affaire.
casablanca
3
@Godders - Pour noter, si vous souhaitez réduire la taille du tableau après sa création à la longueur M, utilisez simplement foo.length = M--- L'information de coupure est perdue. Voyez-le en action ==> jsfiddle.net/ACMXp
Peter Ajtai
24
Je ne comprends vraiment pas pourquoi cette réponse a même des votes positifs ... surtout lorsque le PO lui-même convient que cela n'a aucun sens dans quelques commentaires ci-dessus car il aurait pu le faire var n = 45;.
plalx
72
@scunliffe: Veuillez noter que new Array(45);cela ne "crée pas un tableau à 45 éléments" (au même sens que le [undefined,undefined,..undefined]fait). Il "crée plutôt un tableau vide de longueur = 45" ( [undefined x 45]), identique à var foo = []; foo.length=45;. C'est pourquoi forEach, et mapne s'appliquera pas dans ce cas.
tomalec du
1311

Dans ES6, utilisez les méthodes Array from () et keys () .

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

Version plus courte utilisant l' opérateur d'étalement .

[...Array(10).keys()]
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Niko Ruotsalainen
la source
75
Juste une note, cela commencera toujours à 0. Il faudra chaîner a mapau tableau pour ajuster les valeurs ( [...Array(10).keys()].map(x => x++);) pour commencer à 1
Sterling Archer
33
Il suffit de changer map(x => x++)en map(x => ++x)raison de l'incrément de priorité qui se produit après le retour de la valeur :)
Brock
94
Euh quoi!? Pourquoi mapquand vous pouvez simplement slice? [...Array(N+1).keys()].slice(1)
Robin
19
Ou n'utilisez pas keyset seulement 1 carte ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn
60
Ou n'utilisez pas les clés et la carte et passez simplement une fonction de cartographie àfrom Array.from(Array(10), (e,i)=>i+1)
Fabio Antunes
845

Vous pouvez le faire:

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

résultat: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ou avec des valeurs aléatoires:

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

résultat: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915958745, 0.16

Explication

Tout d'abord, notez que Number.call(undefined, N)c'est équivalent à Number(N), qui revient juste N. Nous utiliserons ce fait plus tard.

Array.apply(null, [undefined, undefined, undefined])est équivalent à Array(undefined, undefined, undefined), ce qui produit un tableau à trois éléments et attribue undefinedà chaque élément.

Comment pouvez-vous généraliser cela à N éléments? Considérez comment cela Array()fonctionne, ce qui ressemble à ceci:

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

Depuis ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)accepte également un objet de type tableau de type canard comme deuxième paramètre. Si nous invoquons Array.apply(null, { length: N }), il s'exécutera

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

Nous avons maintenant un tableau à N éléments, chaque élément étant défini sur undefined. Lorsque nous l'appellerons .map(callback, thisArg), chaque élément sera mis au résultat de callback.call(thisArg, element, index, array). Par conséquent, [undefined, undefined, …, undefined].map(Number.call, Number)mapperait chaque élément à (Number.call).call(Number, undefined, index, array), ce qui est le même que Number.call(undefined, index, array), qui, comme nous l'avons observé précédemment, est évalué àindex . Cela complète le tableau dont les éléments sont les mêmes que leur index.

Pourquoi passer par la peine de Array.apply(null, {length: N})au lieu de juste Array(N)? Après tout, les deux expressions résulteraient en un tableau d'éléments N non définis. La différence est que dans la première expression, chaque élément est explicitement défini sur indéfini, tandis que dans la seconde, chaque élément n'a jamais été défini. Selon la documentation de .map():

callbackest invoqué uniquement pour les index du tableau auxquels des valeurs ont été attribuées; il n'est pas appelé pour les index qui ont été supprimés ou auxquels aucune valeur n'a été affectée.

Par conséquent, Array(N)est insuffisant; Array(N).map(Number.call, Number)entraînerait un tableau non initialisé de longueur N .

Compatibilité

Étant donné que cette technique repose sur le comportement Function.prototype.apply()spécifié dans ECMAScript 5, elle ne fonctionnera pas dans les navigateurs pré-ECMAScript 5 tels que Chrome 14 et Internet Explorer 9.

Igor Shubin
la source
62
+1 pour l'intelligence, mais veuillez noter qu'il s'agit d'un ordre de grandeur plus lent qu'une primitive pour la boucle: jsperf.com/array-magic-vs-for
warpech
7
Très intelligent - probablement aussi. L'exploitation du fait que Function.prototype.callle premier paramètre est l' thisobjet à mapper directement sur Array.prototype.maple paramètre de l'itérateur a une certaine brillance.
Noah Freitas
14
C'est vraiment, vraiment intelligent (limite à l'abus de JS). Le point de vue vraiment important ici est l'idiosyncrasie des mapvaleurs non attribuées, à mon avis. Une autre version (et peut-être légèrement plus claire, quoique plus longue) est: Array.apply(null, { length: N }).map(function(element, index) { return index; })
Ben Reich
6
@BenReich Encore mieux (en termes de niveaux d'abus JS): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) ou, en cas de fonctions es6 et flèches, encore plus court: Array.apply(null, new Array(N)).map((_,i) => i)
oddy
1
SI cela renvoie un tableau qui commence à 1, cela répondrait en fait à la question du PO
Sarsaparilla
484

Plusieurs façons d'utiliser ES6

Utilisation de l'opérateur d'étalement ( ...) et de la méthode des clés

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

Remplir / mapper

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

Array.from

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

Array.from et { length: N }pirater

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

Remarque sur le formulaire généralisé

Toutes les formes ci - dessus peuvent produire des tableaux initialisés à des valeurs à peu près tous souhaités en changeant i+1l'expression nécessaire (par exemple i*2, -i, 1+i*2, i%2et etc.). Si l'expression peut être exprimée par une fonction, fla première forme devient simplement

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

Exemples:

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

Puisque le tableau est initialisé avec undefinedsur chaque position, la valeur dev seraundefined

Exemple présentant tous les formulaires

Exemple plus générique avec fonction d'initialisation personnalisée, par fex.

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

ou encore plus simple

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

Abdennour TOUMI
la source
33
Meilleure réponse à mon humble avis. Voir aussi developer.mozilla.org/de/docs/Web/JavaScript/Reference/…
le_m
5
Utilisez k ++ pour les tableaux commençant à 0
Borgboy
1
Si vous voulez incrémenter, n'utilisez pas k++, utilisez ++k.
Alex
4
Attention Array.from n'est pas pris en charge dans IE, sauf si vous le remplissez poly.
Lauren
2
Pour rendre le compilateur TS heureux, pensez à remplacer le paramètre inutilisé par lodash: Array.from ({longueur: 5}, (_, k) => k + 1);
Journeycorner
297

Les tableaux gèrent de manière innée leurs longueurs. Lorsqu'ils sont parcourus, leurs index peuvent être conservés en mémoire et référencés à ce point. Si un indice aléatoire doit être connu, leindexOf méthode peut être utilisée.


Cela dit, pour vos besoins, vous pouvez simplement déclarer un tableau d'une certaine taille:

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

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

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


ES6

Propagé

L'utilisation de l'opérateur ...et de la keysméthode spread ( ) vous permet de créer un tableau temporaire de taille N pour produire les index, puis un nouveau tableau qui peut être affecté à votre variable:

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

Remplir / mapper

Vous pouvez d'abord créer la taille du tableau dont vous avez besoin, le remplir avec undefined puis créer un nouveau tableau à l'aide de map, qui définit chaque élément sur l'index.

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

Array.from

Cela devrait être l'initialisation à la longueur de taille N et remplir le tableau en un seul passage.

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



Au lieu des commentaires et de la confusion, si vous vouliez vraiment capturer les valeurs de 1..N dans les exemples ci-dessus, il y a quelques options:

  1. si l'index est disponible, vous pouvez simplement l'incrémenter d'une unité (par exemple, ++i ).
  2. dans les cas où l'index n'est pas utilisé - et peut-être une manière plus efficace - consiste à créer votre tableau mais à faire N représenter N + 1, puis à décaler le front.

    Donc, si vous désirez 100 numéros:

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




vol7ron
la source
Je crois que cela est utile lorsque le tableau de nombres est utilisé pour des données qui ne peuvent pas être traitées à la réception. (Comme un modèle HTML qui ne fait que remplacer des valeurs.)
Neil Monroe
Pourquoi quelqu'un ferait cela est d'avoir un tableau de nombres pour remplir une liste déroulante, donnant à l'utilisateur un choix de 1 à 10. Un petit tableau à la main [1,2,3 ... 10] est logique, mais si c'est de 1 à 50? Et si le numéro de fin change?
CigarDoug
@CigarDoug Je ne doute pas qu'il existe un cas d'utilisation, mais je suppose qu'il est petit. Pourquoi un tableau de nombres serait-il nécessaire, généralement lors de l'itération sur un tableau, un index serait utilisé dans le cadre de la construction de la boucle - soit comme argument de la fonction de corps en boucle, soit comme variable de compteur - il est donc trivial de conserver le tableau de nombres pour simplement créer un tableau de largeur spécifiée, ou simplement une variable qui contient la limite supérieure du tableau. Je peux penser à quelques cas d'utilisation, mais aucun d'entre eux n'avait été exprimé par l'OP
vol7ron
4
Comme je l'ai dit, je dois remplir une liste déroulante avec les chiffres de 1 à 10. C'est tout. Il y a un cas d'utilisation, MON cas d'utilisation. C'est comme ça que j'ai trouvé cette page. Donc, construire un tableau à la main était moins compliqué que tout ce que j'ai vu ici. Mes exigences ne sont donc pas celles du PO. Mais j'ai ma réponse.
CigarDoug
1
@ vol7ron Il y a un cas d'utilisation, j'en ai aussi un. En angulaire, en pagination, je souhaite afficher les pages du pied de page cliquables. Je boucle donc les éléments dans une vue avec * ngFor = "let p of pagesCounter". Vous avez une meilleure solution pour ça? BTW, consultez stackoverflow.com/questions/36354325/…
Dalibor
186

Dans ES6, vous pouvez faire:

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

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

Edit: Changé Array(45)pour Array(N)depuis que vous avez mis à jour la question.

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

Nate
la source
3
+1 parce que c'est un grand O meilleur que la .join.splitversion méchante - mais je pense toujours que l'humble boucle est meilleure.
Robin
Je suis d'accord @Robin - La complexité algorithmique mise à part, l'humble boucle est toujours plus lisible. Cependant, avec l'avènement des lambdas à Java, je pense que mapcela deviendra bientôt un standard pour des choses comme ça.
Nate
4
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
Robin
8
Je ne comprends pas pourquoi .fill()c'est nécessaire. Je vois que c'est quand je teste sur la repl du nœud, mais depuis Array(1)[0] === undefined, quelle différence fait l'appel à fill () Array(1).fill(undefined)?
Dominic
11
Pour toute autre personne intéressée, la différence entre Array (N) et Array (N) .fill () est bien expliquée ici
Dominic
108

Utilisez la méthode Underscore _.range très populaire

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

_.range(10); // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11); // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5); // => [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1); //  => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0); // => []
Evan
la source
Impressionnant. Montrez-moi un grand projet qui n'utilise pas de soulignement de toute façon ...
Erez Cohen
63
function range(start, end) {
    var foo = [];
    for (var i = start; i <= end; i++) {
        foo.push(i);
    }
    return foo;
}

Puis appelé par

var foo = range(1, 5);

Il n'y a pas de méthode intégrée pour le faire en Javascript, mais c'est une fonction utilitaire parfaitement valide à créer si vous devez le faire plus d'une fois.

Edit: À mon avis, ce qui suit est une meilleure fonction de gamme. Peut-être juste parce que je suis biaisé par LINQ, mais je pense que c'est plus utile dans plus de cas. Votre kilométrage peut varier.

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

    var foo = [];
    for (var i = 0; i < count; i++) {
        foo.push(start + i);
    }
    return foo;
}
Ian Henry
la source
2
J'aime ça. Si vous vouliez aller plus loin avec lui, vous pourriez le déclarer comme Array.prototype.range = function (start, end) {...} ;. Ensuite, vous pouvez appeler range (x, y) sur n'importe quel objet Array.
Zach Rattner
8
Faites-en plutôt une méthode Arrayau lieu de Array.prototypecar il n'y a aucune raison (elle pourrait même être considérée comme plutôt stupide) d'avoir cette méthode sur chaque tableau.
admettre le
9
Array.range(1, 5)serait probablement plus approprié, mais il y a quelque chose de cool dans l'écriture [].range(1, 5).
MooGoo
"Faites-en plutôt une méthode d'Array au lieu d'Array.prototype" - Quelle est la différence? Vous voulez dire sur un tableau spécifique uniquement?
pilau
3
@pilau Tout comme le dit Adam, cela a l'air bizarre. Si c'est sur le prototype, vous pouvez dire foo = [1, 2, 3]; bar = foo.range(0, 10);. Mais c'est juste ... déroutant. bar = Array.range(0, 10)est beaucoup plus clair et explicite. La plage n'a rien à voir avec l'instance, il n'y a donc aucune raison d'en faire une méthode d'instance.
Ian Henry
53

le moyen le plus rapide de remplir une Arrayv8 est:

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

le résultat sera: [0, 1, 2, 3, 4]

alex dykyі
la source
est-il possible de le faire sans la variable supplémentaire _
bluejayke
@bluejayke no :(
alex dykyі
dur, savez-vous quel est le code source de .map? Je ne suis pas sûr que ce soit plus rapide qu'une boucle for, mais sinon, théoriquement, nous pouvons simplement définir la propriété et en créer une nouvelle
bluejayke
49

Cette question a beaucoup de réponses compliquées, mais une simple ligne:

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

De plus, bien que ce qui précède soit court (et soigné) à écrire, je pense que ce qui suit est un peu plus rapide (pour une longueur maximale de:

127, Int8,

255, Uint8,

32 767, Int16,

65,535, Uint16,

2.147.483.647, Int32,

4 294 967 295, Uint32.

(basé sur les valeurs entières max ), voici aussi plus sur les tableaux typés ):

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

Bien que cette solution ne soit pas aussi idéale, car elle crée deux tableaux et utilise la déclaration de variable supplémentaire "$" (je ne sais pas comment contourner cela en utilisant cette méthode). Je pense que la solution suivante est le moyen le plus rapide possible de le faire:

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

À tout moment après cette instruction, vous pouvez simplement utiliser la variable "arr" dans la portée actuelle;

Si vous voulez en faire une fonction simple (avec quelques vérifications de base):

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

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



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

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

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

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

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


ainsi, avec la fonction ci-dessus, le "simple one-liner" super-lent ci-dessus devient le super-rapide, encore plus court:

range(1,14000);
bluejayke
la source
@JVG mais pas pour la fonction plus rapide?
bluejayke
Exactement raison. C'est cette simple doublure que tout le monde recherche!
supersan
@supersan bien que son super lent :)
bluejayke
Javascript moderne avec la nouvelle fillméthode:Array(255).fill(0,0,255)
cacoder
@cacoder à quelle vitesse est-il, combien de tableaux crée-t-il et combien d'itérations?
bluejayke
42

Vous pouvez utiliser ceci:

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

par exemple

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

créera le tableau suivant:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
nktssh
la source
Et pourquoi pas new Array(10).join().split(',').map(function() {return ++arguments[1]});?
super
1
@Murplyx pour certains cas, la fonction avec des arguments à l'intérieur ne sera pas optimisée par le moteur JS (vrai même pour V8, voir jsperf.com/arguments-vs-array-argument/2 )
nktssh
4
C'est une solution intéressante mais elle est tout à fait impraticable - avoir à analyser le tableau 3 fois (une fois pour join, une fois pour splitet une fois pour la chose que vous voulez réellement faire) n'est tout simplement pas agréable - je sais qu'ils semblent être tombés en disgrâce pour une raison quelconque, mais il serait bien préférable d'utiliser simplement une bonne boucle à l' ancienne !
Robin
42

ES6, cela fera l'affaire:

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

Découvrez le résultat:

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

Christian
la source
5
en fait, ils ont demandé 1..N, pas 0..N-1
YakovL
1
oui, [...Array(N + 1).keys()].slice(1)donnera 1..N
David G
Pour une raison quelconque, cette solution ne fonctionne pas dans l'application Production Version from Expo (react-native). [...Array(N + 1).keys()]ce code retourne un tableau vide, mais juste en mode production, l'utilisation du mode développement fonctionne.
FabianoLothor
3
La .keys()réponse a déjà été donnée il y a des années et compte plus de 500 votes positifs. Qu'y ajoute votre réponse?
Dan Dascalescu
39

Si vous utilisez d3.js dans votre application comme je le suis, D3 fournit une fonction d'assistance qui le fait pour vous.

Donc, pour obtenir un tableau de 0 à 4, c'est aussi simple que:

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

et pour obtenir un tableau de 1 à 5, comme vous le demandiez:

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

Consultez ce tutoriel pour plus d'informations.

Tyler Rick
la source
Ce commentaire m'a donné l'idée de rechercher la fonction range () dans RamdaJS, qui se trouve être la bibliothèque JS avec laquelle je travaille sur mon projet actuel. Parfait.
morphatique
39

Utilisation de l'opérateur d'étalement ES2015 / ES6

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

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

Vlad Bezden
la source
7
i + 1aurait plus de sens que ++i.
Vincent Cantin
38

C'est probablement le moyen le plus rapide pour générer un tableau de nombres

Le plus court

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

En ligne

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

Si vous voulez partir de 1

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

Vous voulez une fonction?

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

POURQUOI?

  1. while est la boucle la plus rapide

  2. Le réglage direct est plus rapide que push

  3. [] est plus rapide que new Array(10)

  4. c'est court ... regardez le premier code. puis regardez toutes les autres fonctions ici.

Si vous aimez ne peut pas vivre sans pour

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

ou

for(var a=[],b=7;b--;a[b]=b+1); //a=[1,2,3,4,5,6,7]
cocco
la source
8
Il serait préférable de sauvegarder ces revendications avec des repères. Essayez jsperf.com .
Matt Ball
2
lol jsperf ... pls Matt juste parce que vous n'aimez pas ma réponse arrêtez de voter pour mes autres ... stackoverflow.com/a/18344296/2450730 ... utilisez console.time () ou comment on l'appelle ... PAS jsperf .
cocco
4
Pour info: comme John Reisig l'a publié pour la première fois il y a quelques années - sur certaines plateformes (c'est-à-dire Windows: P), le temps est envoyé au navigateur toutes les 16 ms. Il existe également d'autres problèmes avec la mesure du temps d'exécution dans des environnements multitâches. jsperf.com a implémenté l'exécution des tests afin qu'ils soient statistiquement corrects. Il est correct de courir console.time()pour avoir une intuition, mais pour une preuve, vous avez besoin de jsperf.com ET cela vous montre les résultats de cross-browser d'autres personnes (matériel différent, etc.)
naugtur
3
@cocco c'est incorrect:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav
5
@ cocco— tandis que n'est pas toujours plus rapide que les autres boucles. Dans certains navigateurs, une boucle décrémentation while est beaucoup plus lente qu'une boucle for, vous ne pouvez pas faire de déclarations générales sur les performances javascript comme ça car il y a tellement d'implémentations avec autant d'optimisations différentes. Cependant, en général, j'aime votre approche. ;-)
RobG
32

Si vous utilisez lodash, vous pouvez utiliser _.range :

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

Crée un tableau de nombres (positifs et / ou négatifs) progressant du début à la fin, mais sans les inclure. Une étape de -1 est utilisée si un début négatif est spécifié sans fin ni étape. Si end n'est pas spécifié, il est défini pour commencer par start puis défini sur 0.

Exemples:

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

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

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

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

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

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

_.range(0);
// ➜ []
Hongbo Miao
la source
32

la nouvelle façon de remplir Arrayest:

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

le résultat sera: [0, 1, 2, 3, 4]

alex dykyі
la source
C'est une très bonne réponse, bien que techniquement la question soit de 1-N, pas de 0- (N-1)
bluejayke
30

avec ES6 vous pouvez faire:

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

la source
Étant donné que les valeurs du tableau sont réellement remplies à l'aide de cette solution, mapet forEachfonctionneront.
dontmentionthebackup
27

Rapport de synthèse final .. Drrruummm Rolll -

Il s'agit du code le plus court pour générer un tableau de taille N (ici 10) sans utiliser ES6 . La version ci-dessus de Cocco est proche mais pas la plus courte.

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

Mais le vainqueur incontesté de ce golf Code (compétition pour résoudre un problème particulier dans le moins d'octets de code source) est Niko Ruotsalainen . Utilisation de Array Constructor et de l' opérateur d'étalement ES6 . (La plupart de la syntaxe ES6 est du typeScript valide, mais ce n'est pas le cas. Soyez donc judicieux lorsque vous l'utilisez)

[...Array(10).keys()]
saveur
la source
Pourquoi voter contre? Longue liste de réponses difficile à suivre, donc j'ai pensé à résumer.
sapy
n'est-ce pas 0-10? [... Array (10) .keys ()]
Greg
Webstorm suggère (nouveau tableau (10)). Keys (), est-ce vrai?
Guy
(new Array (10)). keys (), retourne ArrayIterator {}, pas le tableau
sapy
Cela crée une variable globale a. La boucle devrait êtrefor(var a=[];n--;a[n]=n+1)
kube
20

Il y a une autre façon dans ES6, en utilisant Array.from qui prend 2 arguments, le premier est un arrayLike (dans ce cas un objet avec lengthpropriété), et le second est une fonction de mappage (dans ce cas, nous mappons l'élément à son index)

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

c'est plus court et peut être utilisé pour d'autres séquences comme la génération de nombres pairs

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

Cela a également de meilleures performances que la plupart des autres moyens car il ne boucle qu'une seule fois à travers la baie. Vérifiez l'extrait de code pour quelques comparaisons

// open the dev console to see results

count = 100000

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

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

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

gafi
la source
Hé c'est bien, j'aime ça. Cependant, il ne renvoie pas les résultats attendus par OP. Pour ce faire, il devrait être écrit commeArray.from({length:N}, (v,i) => i+1)
CervEd
Ces hacks Neato sont encore 5 à 10 fois plus lents qu'un bon vieux pour la boucle .
Dan Dascalescu
16

Utilisation de nouvelles méthodes Array et de la =>syntaxe de fonction du standard ES6 (uniquement Firefox au moment de la rédaction).

En remplissant les trous avec undefined:

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

Array.fromtransforme les "trous" en undefineddonc Array.mapfonctionne comme prévu:

Array.from(Array(5)).map((_, i) => i + 1)
szymzet
la source
7
De même, vous pouvez également effectuer les opérations suivantes dans ES6: Array.from({length: N}, (v, k) => k).
XåpplI'-I0llwlg'I -
L'approche de Xappli est préférée: Array.from a été créé pour presque ce scénario exact, et cela implique un rappel de mappage. C'est une excellente solution au problème général de vouloir utiliser des méthodes Array sur quelque chose comme un tableau, sans recourir à des approches verbeuses comme Array.prototype.map.call, par exemple pour les NodeLists renvoyées document.querySelectorAll. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Josh de Qaribou du
Je pèse cela par rapport à la syntaxe de la plage de soulignement, et la plage se lit mieux.
ooolala
Techniquement, ce n'est pas Array.fromce qui transforme les valeurs clairsemées en indéfinies. Plutôt Array(5)est appelé comme un objet arguments qui à son tour interprète les valeurs éparses comme des valeurs indéfinies :)
CervEd
15

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

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

alex dykyі
la source
Agréable! Peut également écrire ceci un peu plus succinctement comme[...Array(9)].map((_, i) => i)
Eamonn O'Brien-Strain
13
for(var i,a=[i=0];i<10;a[i++]=i);

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

SammieFox
la source
Vraiment génial! Tx!
Pedro Ferreira
12

Dans ES6:

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

ES5:

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

Juste une autre version ES6 .

En utilisant le Array.fromdeuxième argument facultatif:

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

Nous pouvons construire le tableau numéroté à partir des Array(10)positions vides :

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

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

zurfyx
la source
C'est plus compliqué et ~ 10 fois plus lent que [...Array(11).keys()].slice(1).
Dan Dascalescu
10

Il semble que la seule saveur qui ne figure pas actuellement dans cette liste de réponses plutôt complète est celle qui comprend un générateur; pour y remédier:

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

qui peut être utilisé ainsi:

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

La bonne chose à ce sujet est que vous n'avez pas seulement à incrémenter ... Pour vous inspirer de la réponse donnée par igor-shubin, vous pouvez créer un tableau de randoms très facilement:

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

Et plutôt que quelque chose de long sur le plan opérationnel comme:

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

vous pourriez plutôt faire:

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

Vous pouvez utiliser le remplissage et la carte du tableau à partir d'Es6; tout comme quelques personnes l'ont suggéré dans les réponses qu'elles ont données à cette question. Voici quelques exemples:

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

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

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

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

Je préfère cela parce que je le trouve simple et plus facile.

Gbemi Kadri
la source
9

Utilisation d'ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);
Geoffrey Abdallah
la source
Merci! C'était la réponse la plus élégante à mon avis! On pourrait également utiliser Array.from(Array(n))si l'opérateur de propagation n'est pas pris en charge.
Amit
Au début, je ne savais pas pourquoi vous deviez utiliser l'opérateur d'étalement, mais j'ai lu ce qui suit mapsur MDN : "Il n'est pas appelé pour les éléments manquants du tableau (c'est-à-dire, les index qui n'ont jamais été définis, qui ont été supprimée ou à laquelle aucune valeur n'a été attribuée). "
battmanz
9

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

Retours [0, 1, 2]. Très similaire à l'excellente réponse d' Igor Shubin , mais avec un peu moins de ruse (et un personnage de plus).

Explication:

  • Array(3) // [undefined × 3]Générez un tableau de longueur n = 3. Malheureusement, ce tableau nous est presque inutile, nous devons donc…
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]rendre le tableau itérable. Remarque: null est plus courant que le premier argument de apply mais 0 est plus court.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] puis récupérez les clés du tableau (fonctionne parce que les tableaux sont le type de tableau est un objet avec des index pour les clés.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] et mappez les clés, convertissant les chaînes en nombres.
mLuby
la source