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?

Conta
fonte

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.

jyore
fonte
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.

Blazemonger
fonte
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' ]

Claudio
fonte
33

Você pode usar o lodash: https://lodash.com/docs

_.chunk(['a', 'b', 'c', 'd'], 2);
// → [['a', 'b'], ['c', 'd']]
Alexander Paramonov
fonte
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
}
jfriend00
fonte
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];
tawnos178
fonte
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;
  }, []);
}
Aurelio
fonte
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];
Justin
fonte
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    ] ]
Filipe nicoli
fonte
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.

AFurlepa
fonte
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.

Alf
fonte
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);
Subhankar
fonte
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));

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

dzuc
fonte
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])
}
Ryan
fonte
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);
zgthompson
fonte
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);
Ridwanullah Ibrahim
fonte
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.
Clint
fonte
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.

Siddharth Yadav
fonte
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));

AmitNayek
fonte
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]]
Haures Bogdan
fonte
Você poderia adicionar alguma descrição?
ego