Comment diviser un long tableau en tableaux plus petits, avec JavaScript


100

J'ai un tableau d'e-mails (cela peut être juste 1 e-mail, ou 100 e-mails), et je dois envoyer le tableau avec une requête ajax (que je sais faire), mais je ne peux envoyer qu'un tableau qui a 10 e-mails ou moins. Donc, s'il y a un tableau original de 20 e-mails, je devrai les diviser en 2 tableaux de 10 chacun. ou s'il y a 15 e-mails dans le tableau d'origine, puis 1 tableau de 10 et un autre tableau de 5. J'utilise jQuery, quelle serait la meilleure façon de faire cela?

Réponses:


195

N'utilisez pas jquery ... utilisez du javascript simple

var a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

var b = a.splice(0,10);

//a is now [11,12,13,14,15];
//b is now [1,2,3,4,5,6,7,8,9,10];

Vous pouvez faire une boucle pour obtenir le comportement souhaité.

var a = YOUR_ARRAY;
while(a.length) {
    console.log(a.splice(0,10));
}

Cela vous donnerait 10 éléments à la fois ... si vous avez par exemple 15 éléments, vous obtiendrez 1-10, les 11-15 comme vous le souhaitez.


9
Notez que YOUR_ARRAY sera également consommé (les tableaux sont des objets ...)
Claudio

Ouais, je mettais juste ça parce que a n'est pas descriptif, et j'ai déjà écrit l'exemple en utilisant a ... c'est une ligne de code complètement inutile ... bien que cela me fasse penser ... si vous utilisez ce modèle, vous voudrez peut-être faire une copie
complète

@junvar IDK si ce 1-liner fonctionnait en 2018 (j'en doute sérieusement), mais il échoue lamentablement aujourd'hui. Vous ne devez jamais muter (c'est-à-dire supprimer des éléments) un tableau en cours d'itération, cela jette l'index, c'est-à-dire qu'après chaque suppression, il doit être réajusté du nombre d'éléments supprimés, donc il «saute» et ne consomme pas le tableau entièrement. Essayez-le
Drew Reese le

107
var size = 10; var arrayOfArrays = [];
for (var i=0; i<bigarray.length; i+=size) {
     arrayOfArrays.push(bigarray.slice(i,i+size));
}
console.log(arrayOfArrays);

Contrairement à splice(), slice()est non destructif pour le tableau d'origine.


1
cette solution est meilleure
Maduekwe Pedro

38

Faites une boucle sur le tableau, en l'épissant jusqu'à ce qu'il soit entièrement consommé.



var a = ['a','b','c','d','e','f','g']
  , chunk

while (a.length > 0) {

  chunk = a.splice(0,3)

  console.log(chunk)

}

production


[ 'a', 'b', 'c' ]
[ 'd', 'e', 'f' ]
[ 'g' ]



13

En supposant que vous ne souhaitiez pas détruire le tableau d'origine, vous pouvez utiliser un code comme celui-ci pour diviser le long tableau en tableaux plus petits que vous pouvez ensuite parcourir:

var longArray = [];   // assume this has 100 or more email addresses in it
var shortArrays = [], i, len;

for (i = 0, len = longArray.length; i < len; i += 10) {
    shortArrays.push(longArray.slice(i, i + 10));
}

// now you can iterate over shortArrays which is an 
// array of arrays where each array has 10 or fewer 
// of the original email addresses in it

for (i = 0, len = shortArrays.length; i < len; i++) {
    // shortArrays[i] is an array of email addresss of 10 or less
}

6

Une autre implémentation:

const arr = ["H", "o", "w", " ", "t", "o", " ", "s", "p", "l", "i", "t", " ", "a", " ", "l", "o", "n", "g", " ", "a", "r", "r", "a", "y", " ", "i", "n", "t", "o", " ", "s", "m", "a", "l", "l", "e", "r", " ", "a", "r", "r", "a", "y", "s", ",", " ", "w", "i", "t", "h", " ", "J", "a", "v", "a", "S", "c", "r", "i", "p", "t"];

const size = 3; 
const res = arr.reduce((acc, curr, i) => {
  if ( !(i % size)  ) {    // if index is 0 or can be divided by the `size`...
    acc.push(arr.slice(i, i + size));   // ..push a chunk of the original array to the accumulator
  }
  return acc;
}, []);

// => [["H", "o", "w"], [" ", "t", "o"], [" ", "s", "p"], ["l", "i", "t"], [" ", "a", " "], ["l", "o", "n"], ["g", " ", "a"], ["r", "r", "a"], ["y", " ", "i"], ["n", "t", "o"], [" ", "s", "m"], ["a", "l", "l"], ["e", "r", " "], ["a", "r", "r"], ["a", "y", "s"], [",", " ", "w"], ["i", "t", "h"], [" ", "J", "a"], ["v", "a", "S"], ["c", "r", "i"], ["p", "t"]]

NB - Cela ne modifie pas la matrice d'origine.

Ou, si vous préférez une méthode fonctionnelle, 100% immuable (bien qu'il n'y ait vraiment rien de mal à muter sur place comme ci-dessus) et autonome:

function splitBy(size, list) {
  return list.reduce((acc, curr, i, self) => {
    if ( !(i % size)  ) {  
      return [
          ...acc,
          self.slice(i, i + size),
        ];
    }
    return acc;
  }, []);
}

5

En complément de la réponse de @ jyore , et au cas où vous voudriez toujours conserver le tableau d'origine:

var originalArray = [1,2,3,4,5,6,7,8];

var splitArray = function (arr, size) {

  var arr2 = arr.slice(0),
      arrays = [];

  while (arr2.length > 0) {
      arrays.push(arr2.splice(0, size));
  }

  return arrays;
}

splitArray(originalArray, 2);
// originalArray is still = [1,2,3,4,5,6,7,8];

5

Array.reduce peut être inefficace pour les grands tableaux, en particulier avec l'opérateur mod. Je pense qu'une solution fonctionnelle plus propre (et peut-être plus facile à lire) serait la suivante:

const chunkArray = (arr, size) =>
  arr.length > size
    ? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)]
    : [arr];

3

Une autre méthode:

var longArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var size = 2;

var newArray = new Array(Math.ceil(longArray.length / size)).fill("")
    .map(function() { return this.splice(0, size) }, longArray.slice());

// newArray = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]];

Cela n'affecte pas le tableau d'origine car une copie, faite à l'aide de slice, est passée dans l'argument «this» de map.


3

Je voudrais également partager ma solution. C'est un peu plus verbeux mais ça marche aussi.

var data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

var chunksize = 4;


var chunks = [];

data.forEach((item)=>{
  if(!chunks.length || chunks[chunks.length-1].length == chunksize)
  chunks.push([]);

  chunks[chunks.length-1].push(item);
});

console.log(chunks);

Sortie (formatée):

[ [ 1,  2,  3,  4],
  [ 5,  6,  7,  8],
  [ 9, 10, 11, 12],
  [13, 14, 15    ] ]

2

Une autre implémentation, utilisant Array.reduce (je pense que c'est la seule qui manque!):

const splitArray = (arr, size) =>
{
    if (size === 0) {
        return [];
    }

    return arr.reduce((split, element, index) => {
        index % size === 0 ? split.push([element]) : split[Math.floor(index / size)].push(element);
        return split;
    }, []);
};

Comme beaucoup de solutions ci-dessus, celle-ci est non destructive. Renvoyer un tableau vide lorsque la taille est égale à 0 n'est qu'une convention. Si le ifbloc est omis, vous obtenez une erreur, ce que vous souhaitez peut-être.


1

Vous pouvez jeter un œil à ce code. Simple et efficace.

function chunkArrayInGroups(array, unit) {
var results = [],
length = Math.ceil(array.length / unit);

for (var i = 0; i < length; i++) {
    results.push(array.slice(i * unit, (i + 1) * unit));
}
 return results;
}

chunkArrayInGroups(["a", "b", "c", "d"], 2);

1

Voici une simple doublure

var segment = (arr, n) => arr.reduce((r,e,i) => i%n ? (r[r.length-1].push(e), r)
                                                    : (r.push([e]), r), []),
        arr = Array.from({length: 31}).map((_,i) => i+1);
console.log(segment(arr,7));


1

Plus compact:

const chunk = (xs, size) =>
  xs.map((_, i) =>
    (i % size === 0 ? xs.slice(i, i + size) : null)).filter(Boolean);
    
// Usage:
const sampleArray = new Array(33).fill(undefined).map((_, i) => i);

console.log(chunk(sampleArray, 5));


0

Si vous voulez une méthode qui ne modifie pas le tableau existant, essayez ceci:

let oldArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
let newArray = [];
let size = 3; // Size of chunks you are after
let j = 0; // This helps us keep track of the child arrays

for (var i = 0; i < oldArray.length; i++) {
  if (i % size === 0) {
    j++
  }
  if(!newArray[j]) newArray[j] = [];
  newArray[j].push(oldArray[i])
}

0
function chunkArrayInGroups(arr, size) {
    var newArr=[];

    for (var i=0; arr.length>size; i++){
    newArr.push(arr.splice(0,size));
    }
    newArr.push(arr.slice(0));
    return newArr;

}

chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3);

n'oubliez pas de créer: newArr = [] une variable locale
zgthompson

Les réponses à code uniquement ont tendance à être signalées, puis supprimées comme étant de faible qualité. Pourriez-vous nous expliquer comment cela résout le problème initial?
Graham

cela ne fonctionne pas si la taille du bloc est inférieure à la taille du tableau d'entrée.
r3wt

0
function chunkArrayInGroups(arr, size) {
    var newArr=[];

    for (var i=0; i < arr.length; i+= size){
    newArr.push(arr.slice(i,i+size));
    }
    return newArr;

}

chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3);

2
Bienvenue dans stackoverflow. Votre réponse serait améliorée en ajoutant quelques explications.
Simon.SA

0

en tant que fonction

var arrayChunk = function (array, chunkSize) {
            var arrayOfArrays = [];

            if (array.length <= chunkSize) {
                arrayOfArrays.push(array);
            } else {
                for (var i=0; i<array.length; i+=chunkSize) {
                    arrayOfArrays.push(array.slice(i,i+chunkSize));
                }
            }
            return arrayOfArrays;
        }

utiliser

arrayChunk(originalArray, 10) //10 being the chunk size.

0

en utilisant la récursivité

let myArr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
let size = 4; //Math.sqrt(myArr.length); --> For a n x n matrix
let tempArr = [];
function createMatrix(arr, i) {
    if (arr.length !== 0) {
      if(i % size == 0) {
        tempArr.push(arr.splice(0,size))
      } 
      createMatrix(arr, i - 1)
    }
}
createMatrix(myArr, myArr.length);
console.log(tempArr);

Remarque: le tableau existant, c'est-à-dire myArr, sera modifié.


0

en utilisant un prototype, nous pouvons définir directement la classe de tableau

Array.prototype.chunk = function(n) {
  if (!this.length) {
    return [];
  }
  return [this.slice(0, n)].concat(this.slice(n).chunk(n));
};
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].chunk(5));


0
const originalArr = [1,2,3,4,5,6,7,8,9,10,11];
const splittedArray = [];
  while (originalArr.length > 0) {
    splittedArray.push(originalArr.splice(0,range));  
  }

sortie pour la plage 3

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

sortie pour la plage 4

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

Pourriez-vous s'il vous plaît ajouter une description?
ego
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.