Cómo dividir una matriz larga en matrices más pequeñas, con JavaScript

100

Tengo una variedad de correos electrónicos (puede ser solo 1 correo electrónico o 100 correos electrónicos) y necesito enviar la matriz con una solicitud ajax (que sé cómo hacerlo), pero solo puedo enviar una matriz que tiene 10 o menos correos electrónicos en él. Entonces, si hay una matriz original de 20 correos electrónicos, tendré que dividirlos en 2 matrices de 10 cada una. o si hay 15 correos electrónicos en la matriz original, luego 1 matriz de 10 y otra matriz de 5. Estoy usando jQuery, ¿cuál sería la mejor manera de hacer esto?

Cuenta
fuente

Respuestas:

195

No use jquery ... use 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];

Puede repetir esto para obtener el comportamiento que desea.

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

Esto le daría 10 elementos a la vez ... si tiene, digamos, 15 elementos, obtendría 1-10, el 11-15 como quisiera.

jyore
fuente
9
Tenga en cuenta que YOUR_ARRAY también se consumirá (la matriz son objetos ...)
Claudio
Sí, solo estaba poniendo eso porque a no es descriptivo, y ya escribí el ejemplo usando un ... es una línea de código completamente innecesaria ... Aunque, eso me hace pensar ... si usas este patrón, es posible que desee hacer una copia profunda en una matriz de trabajo para no interrumpir su original
jyore
@junvar IDK si ese 1-liner funcionó en 2018 (dudo seriamente que lo hiciera), pero hoy falla miserablemente. Debe nunca se mutan (es decir, elementos quitar) un ser array iterado sobre, se arroja en el índice, es decir, después de cada eliminación debe ser re-ajustado por el número de elementos eliminado, por lo que "salta por delante" y no consume el matriz por completo. Pruébalo
Drew Reese
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);

A diferencia de splice(), slice()no es destructivo para la matriz original.

Blazemonger
fuente
1
esta solución es mejor
Maduekwe Pedro
38

Simplemente recorra la matriz, uniéndola hasta que se consuma por completo.



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

while (a.length > 0) {

  chunk = a.splice(0,3)

  console.log(chunk)

}

salida


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

Claudio
fuente
13

Suponiendo que no desea destruir la matriz original, puede usar un código como este para dividir la matriz larga en matrices más pequeñas sobre las que luego puede 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
fuente
6

Otra implementación:

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: esto no modifica la matriz original.

O, si prefiere un método funcional, 100% inmutable (aunque realmente no hay nada malo en mutar en un lugar como se hizo anteriormente) y autónomo:

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

Como complemento de la respuesta de @ jyore , y en caso de que aún desee mantener la 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
fuente
5

Array.reduce podría ser ineficaz para arreglos grandes, especialmente con el operador mod. Creo que una solución funcional más limpia (y posiblemente más fácil de leer) sería esta:

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

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

Esto no afecta a la matriz original, ya que una copia, realizada con un segmento, se pasa al argumento "este" del mapa.

AFurlepa
fuente
3

También me gustaría compartir mi solución. Es un poco más detallado, pero también 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);

Salida (formateada):

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

Otra implementación, usando Array.reduce (¡creo que es la ú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 muchas de las soluciones anteriores, esta no es destructiva. Devolver una matriz vacía cuando el tamaño es 0 es solo una convención. Si ifse omite el bloque, obtendrá un error, que podría ser lo que desea.

Alf
fuente
1

Puedes echar un vistazo a este código. Simple y efectivo.

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
fuente
1

Aquí hay un trazador de líneas simple

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
fuente
1

Mas 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
fuente
0

Si desea un método que no modifique la matriz existente, intente esto:

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
fuente
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
fuente
no olvide hacer: newArr = [] una variable local
zgthompson
Las respuestas de solo código tienden a marcarse y luego eliminarse por ser de baja calidad. ¿Podría proporcionar algún comentario sobre cómo esto resuelve el problema original?
Graham
esto no funciona si el tamaño del fragmento es menor que el tamaño de la 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
fuente
2
Bienvenido a stackoverflow. Su respuesta se mejoraría agregando alguna explicación.
Simon.SA
0

como una función

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
fuente
0

usando recursividad

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: La matriz existente, es decir, myArr, se modificará.

Siddharth Yadav
fuente
0

usando el prototipo podemos configurarlo directamente en la clase de matriz

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

salida para rango 3

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

salida para rango 4

splittedArray === [[1,2,3,4][5,6,7,8][9,10,11]]
Haures Bogdan
fuente
¿Podría agregar alguna descripción?
ego