Como dividir um array longo em arrays menores, com JavaScript


104

Eu tenho uma matriz de e-mails (pode ser apenas 1 e-mail ou 100 e-mails) e preciso enviar a matriz com uma solicitação de ajax (que sei fazer), mas só posso enviar uma matriz que tenha 10 ou menos e-mails nele. Portanto, se houver um array original de 20 e-mails, terei de dividi-los em 2 arrays de 10 cada. ou se houver 15 e-mails no array original, depois 1 array de 10 e outro array de 5. Estou usando jQuery, qual seria a melhor maneira de fazer isso?

Respostas:


200

Não use jquery ... use javascript puro

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];

Você pode fazer um loop para obter o comportamento desejado.

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

Isso lhe daria 10 elementos por vez ... se você tivesse, digamos, 15 elementos, obteria 1-10, os 11-15 conforme desejasse.


9
Note que YOUR_ARRAY também será consumido (array são objetos ...)
Claudio

Sim, eu estava colocando isso porque a não é descritivo e já escrevi o exemplo usando um ... é uma linha de código completamente desnecessária ... Embora, isso me faça pensar ... se estiver usando esse padrão, você pode querer fazer uma cópia profunda em um array de trabalho para não atrapalhar seu original
jyore

@junvar IDK se aquele 1-liner funcionou em 2018 (duvido seriamente que sim), mas hoje falha terrivelmente. Você nunca deve alterar (ou seja, remover elementos) uma matriz que está sendo iterada, ela tira o índice, ou seja, após cada remoção, ela deve ser reajustada pelo número de elementos removidos, para que "pule para a frente" e não consuma o array inteiramente. Experimente
Drew Reese,

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

Ao contrário splice(), slice()não é destrutivo para o array original.


1
esta solução é melhor
Maduekwe Pedro

38

Apenas faça um loop sobre a matriz, emendando-a até que esteja totalmente consumida.



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

while (a.length > 0) {

  chunk = a.splice(0,3)

  console.log(chunk)

}

resultado


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



13

Supondo que você não queira destruir o array original, você pode usar um código como este para dividir o array longo em arrays menores que você pode iterar:

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
}

7

Array.reduce pode ser ineficiente para grandes arrays, especialmente com o operador mod. Acho que uma solução funcional mais limpa (e possivelmente mais fácil de ler) seria esta:

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

6

Outra implementação:

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 - Isso não modifica a matriz original.

Ou, se você preferir um método funcional, 100% imutável (embora não haja realmente nada de ruim em fazer mutações no local como feito acima) e um método autocontido:

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

5

Como suplemento à resposta de @jyore , e caso você ainda queira manter a matriz original:

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];

4

Eu gostaria de compartilhar minha solução também. É um pouco mais detalhado, mas também funciona.

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);

Saída (formatado):

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

3

Outro método:

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]];

Isso não afeta o array original, pois uma cópia, feita usando slice, é passada para o argumento 'this' do mapa.


2

Outra implementação, usando Array.reduce (acho que é a única que falta!):

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;
    }, []);
};

Como muitas soluções acima, esta não é destrutiva. Retornar um array vazio quando o tamanho é 0 é apenas uma convenção. Se o ifbloco for omitido, você obterá um erro, que pode ser o que você deseja.


1

Você pode dar uma olhada neste código. Simples e eficaz.

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

Aqui está um forro simples

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

Mais compacto:

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

Se você quiser um método que não modifique a matriz existente, tente isto:

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ão se esqueça de fazer: newArr = [] uma variável local
zgthompson

Respostas somente de código tendem a ser sinalizadas e, em seguida, excluídas por serem de baixa qualidade. Você poderia fornecer alguns comentários sobre como isso resolve o problema original?
Graham

isso não funciona se o tamanho do bloco for menor que o tamanho da matriz de entrada.
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
Bem-vindo ao stackoverflow. Sua resposta seria melhorada com alguma explicação.
Simon.SA

0

Como uma função

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;
        }

usar

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

0

usando recursão

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);

Nota: O array existente, ou seja, myArr, será modificado.


0

usando protótipo, podemos definir diretamente para a classe de array

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));  
  }

saída para a faixa 3

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

saída para a faixa 4

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

Você poderia adicionar alguma descrição?
ego
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.