Disons que j'ai un tableau Javascript qui ressemble à ceci:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
Quelle approche serait appropriée pour fragmenter (diviser) le tableau en plusieurs tableaux plus petits avec, disons, 10 éléments au maximum?
javascript
arrays
split
Industriel
la source
la source
const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []
ce qui est agréable et court mais semble prendre environ 256 × aussi longtemps que la réponse de @ AymKdn pour 1 000 éléments, et 1 058 × aussi longtemps pour 10 000 éléments!Réponses:
La méthode array.slice peut extraire une tranche du début, du milieu ou de la fin d'un tableau à toutes fins utiles, sans modifier le tableau d'origine.
la source
chunk
être0
. (boucle infinie)const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));
.Modifié à partir d'une réponse de dbaseman: https://stackoverflow.com/a/10456344/711085
addendum mineur :
Je dois souligner que ce qui précède est une solution de contournement pas si élégante (dans mon esprit) à utiliser
Array.map
. Il fait essentiellement ce qui suit, où ~ est la concaténation:Il a le même temps d'exécution asymptotique que la méthode ci-dessous, mais peut-être un facteur constant pire en raison de la création de listes vides. On pourrait réécrire ceci comme suit (principalement la même que la méthode de Blazemonger, c'est pourquoi je n'ai pas soumis cette réponse à l'origine):
Méthode plus efficace:
De nos jours, ma voie préférée est celle ci-dessus, ou l'une des suivantes:
Démo:
Ou si vous ne voulez pas d'une fonction Array.range, c'est en fait juste une ligne (à l'exception du fluff):
ou
la source
chunk
fonction sur le tableau ne l'emporte pas vraiment sur la complexité supplémentaire que vous ajoutez et les bugs subtils que peut causer le fait de jouer avec des prototypes intégrés.array.map(function(i)
pasarray.map(function(elem,i)
siVoici une version ES6 utilisant réduire
Et vous êtes prêt à enchaîner davantage la carte / réduire les transformations. Votre tableau d'entrée est laissé intact
Si vous préférez une version plus courte mais moins lisible, vous pouvez en saupoudrer
concat
dans le mix pour le même résultat final:la source
5/2 = 2.5
etMath.floor(2.5) = 2
donc l'élément avec l'index 5 sera placé dans le seau 2Essayez d'éviter le bourrage avec des prototypes natifs, y compris Array.prototype, si vous ne savez pas qui va consommer votre code (tiers, collègues, vous-même à une date ultérieure, etc.).
Il existe des moyens d'étendre les prototypes en toute sécurité (mais pas dans tous les navigateurs) et il existe des moyens de consommer en toute sécurité des objets créés à partir de prototypes étendus, mais une meilleure règle de base est de suivre le principe de la moindre surprise et d'éviter complètement ces pratiques.
Si vous avez un peu de temps, regardez la conférence JSConf 2011 d'Andrew Dupont, "Tout est permis: extension des fonctions intégrées" , pour une bonne discussion sur ce sujet.
Mais revenons à la question, bien que les solutions ci-dessus fonctionnent, elles sont trop complexes et nécessitent des frais de calcul inutiles. Voici ma solution:
la source
J'ai testé les différentes réponses sur jsperf.com. Le résultat est disponible ici: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds
Et la fonction la plus rapide (et qui fonctionne à partir d'IE8) est celle-ci:
la source
function chunk<T>(array: T[], chunkSize: number): T[][] { const R = []; for (let i = 0, len = array.length; i < len; i += chunkSize) R.push(array.slice(i, i + chunkSize)); return R; }
Je préfère utiliser la méthode d' épissure :
la source
var clone = [...array]
puis effectuez la vérification de la longueur et l'épissage sur ce tableau cloné.array = array.slice()
créer une copie superficielle.Une doublure dans ECMA 6
la source
list
tableau d' origine.map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
Ancienne question: nouvelle réponse! En fait, je travaillais avec une réponse à cette question et j'ai demandé à un ami de l'améliorer! Voici donc:
la source
.length
est beaucoup plus grand que la taille de blocn
). S'il s'agissait d'un langage paresseux (contrairement au javascript), cet algorithme ne souffrirait pas du temps O (N ^ 2). Cela dit, l'implémentation récursive est élégante. Vous pouvez probablement le modifier pour améliorer les performances en définissant d'abord une fonction d'assistance qui se répètearray,position
, puis en répartissant :Array.prototype.chunk
renvoie [votre fonction d'assistance] (...)var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
De nos jours, vous pouvez utiliser la fonction chunk de lodash pour diviser le tableau en plus petits tableaux https://lodash.com/docs#chunk Plus besoin de jouer avec les boucles!
la source
Il y a eu beaucoup de réponses mais voici ce que j'utilise:
Tout d'abord, recherchez un reste lorsque vous divisez l'index par la taille du bloc.
S'il y a un reste, renvoyez simplement le tableau d'accumulateurs.
S'il n'y a pas de reste, alors l'index est divisible par la taille du morceau, alors prenez une tranche du tableau d'origine (en commençant à l'index actuel) et ajoutez-la au tableau d'accumulateurs.
Ainsi, le tableau d'accumulateurs renvoyé pour chaque itération de réduction ressemble à ceci:
la source
Utilisation de générateurs
la source
Ok, commençons par un assez serré:
Qui est utilisé comme ceci:
Ensuite, nous avons cette fonction de réduction serrée:
Qui est utilisé comme ceci:
Puisqu'un chaton meurt quand nous nous lions
this
à un nombre, nous pouvons effectuer un curry manuel comme ceci à la place:Qui est utilisé comme ceci:
Ensuite, la fonction encore assez serrée qui fait tout en une seule fois:
la source
(p[i/n|0] || (p[i/n|0] = []))
, donc vous n'attribuez pas de valeur, si ce n'est pas nécessaire ...Je visais à créer une solution simple non mutante en ES6 pur. Les particularités en javascript obligent à remplir le tableau vide avant le mappage :-(
Cette version avec récursivité semble plus simple et plus convaincante:
Les fonctions de tableau ridiculement faibles d'ES6 font de bons puzzles :-)
la source
0
dufill
, ce qui rend lefill
look un peu plus sensible, à mon humble avis.Je pense que c'est une belle solution récursive avec la syntaxe ES6:
la source
Création d'un package npm pour ce https://www.npmjs.com/package/array.chunk
Lors de l'utilisation d'un TypedArray
la source
slice
méthode pourTypedArray
, nous pouvons utiliser à lasubarray
place developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Si vous utilisez la version EcmaScript> = 5.1, vous pouvez implémenter une version fonctionnelle de l'
chunk()
utilisation de array.reduce () qui a une complexité O (N):Explication de chacun
// nbr
ci-dessus:chunkSize
élémentsCurry basé sur
chunkSize
:Vous pouvez ajouter la
chunk()
fonction à l'Array
objet global :la source
la source
la source
L'approche ES2015 suivante fonctionne sans avoir à définir de fonction et directement sur des tableaux anonymes (exemple avec la taille de bloc 2):
Si vous voulez définir une fonction pour cela, vous pouvez le faire comme suit (en améliorant le commentaire de K. sur la réponse de Blazemonger ):
la source
Et ce serait ma contribution à ce sujet. Je suppose que
.reduce()
c'est la meilleure façon.Mais l'implémentation ci-dessus n'est pas très efficace car elle
.reduce()
parcourt toutes lesarr
fonctions. Une approche plus efficace (très proche de la solution impérative la plus rapide) serait d'itérer sur le tableau réduit (à fragmenter) car nous pouvons calculer sa taille à l'avance parMath.ceil(arr/n);
. Une fois que nous avons le tableau de résultats vide commeArray(Math.ceil(arr.length/n)).fill();
le reste, il faut y mapper des tranchesarr
.la source
Utilisez un morceau de lodash
la source
Encore une solution en utilisant
arr.reduce()
:Cette solution est très similaire à la solution de Steve Holgado . Cependant, parce que cette solution n'utilise pas l'étalement des tableaux et ne crée pas de nouveaux tableaux dans la fonction de réduction , c'est plus rapide (voir test jsPerf ) et subjectivement plus lisible (syntaxe plus simple) que l'autre solution.
À chaque nième itération (où n =
size
; à partir de la première itération), le tableau accumulateur (acc
) est ajouté avec un morceau du tableau (arr.slice(i, i + size)
) puis renvoyé. À d'autres itérations, le tableau d'accumulateurs est renvoyé tel quel.Si
size
est égal à zéro, la méthode renvoie un tableau vide. Sisize
est négatif, la méthode renvoie des résultats cassés. Donc, si nécessaire dans votre cas, vous voudrez peut-être faire quelque chose à propos dessize
valeurs négatives ou non positives .Si la vitesse est importante dans votre cas, une simple
for
boucle serait plus rapide que l'utilisationarr.reduce()
(voir le test jsPerf ), et certains trouveront peut-être aussi ce style plus lisible:la source
Pour une solution fonctionnelle, en utilisant Ramda :
Où
popularProducts
est votre tableau d'entrée,5
est la taille du blocla source
Approche unifilaire ES6 basée sur
Array.prototype
reduce
etpush
méthodes:la source
ES6 Générateur Version
la source
const
plutôt.C'est la solution la plus efficace et la plus simple à laquelle je puisse penser:
la source
ES6 propage #ohmy #ftw fonctionnel
la source
Voici une solution récursive qui est l'optimisation des appels de queue.
la source
EDIT: @ mblase75 a ajouté un code plus concis à la réponse précédente pendant que j'écrivais la mienne, donc je recommande d'aller avec sa solution.
Vous pouvez utiliser du code comme celui-ci:
Modifiez la valeur de
arraySize
pour modifier la longueur maximale des petits tableaux.la source
Voici une solution non mutante utilisant uniquement la récursivité et slice ().
Ensuite, utilisez-le simplement comme
splitToChunks([1, 2, 3, 4, 5], 3)
pour obtenir[[1, 2, 3], [4, 5]]
.Voici un violon à essayer: https://jsfiddle.net/6wtrbx6k/2/
la source