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?

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.


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.


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



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
}

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

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

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

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.


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

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.


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

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


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


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

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

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

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.

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á.


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


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

¿Podría agregar alguna descripción?
ego
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.