Jak podzielić długą tablicę na mniejsze tablice za pomocą JavaScript

106

Mam tablicę e-maili (może to być tylko 1 e-mail lub 100 e-maili) i muszę wysłać tablicę z żądaniem ajax (które wiem, jak to zrobić), ale mogę wysłać tylko tablicę, która ma Zawiera 10 lub mniej e-maili. Więc jeśli istnieje oryginalna tablica 20 e-maili, będę musiała podzielić je na 2 tablice po 10 każda. lub jeśli w oryginalnej tablicy jest 15 e-maili, to 1 tablica 10 i druga tablica 5. Używam jQuery, jaki byłby najlepszy sposób na zrobienie tego?

Rachunek
źródło

Odpowiedzi:

201

Nie używaj jquery ... używaj zwykłego javascript

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

Możesz to zapętlić, aby uzyskać pożądane zachowanie.

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

To dałoby ci 10 elementów na raz ... jeśli masz 15 elementów, otrzymasz 1-10, 11-15, tak jak chciałeś.

jyore
źródło
9
Zwróć uwagę, że YOUR_ARRAY również zostanie zużyty (tablica to obiekty ...)
Claudio
Tak, po prostu to umieściłem, ponieważ a nie jest opisowy, a już napisałem ten przykład używając ... to jest całkowicie niepotrzebna linia kodu ... Chociaż to sprawia, że ​​myślę ... jeśli używam tego wzorca, możesz chcieć zrobić głęboką kopię do działającej tablicy, aby nie zakłócać oryginału
jyore
@junvar IDK, jeśli ten 1-liniowy działał w 2018 r. (poważnie wątpię, że tak się stało), ale dzisiaj nie działa. Nigdy nie należy mutować (tj. Usuwać elementów) tablicy podlegającej iteracji, odrzuca ona indeks, tzn. Po każdym usunięciu należy ją ponownie dopasować o liczbę usuwanych elementów, aby „przeskakiwała do przodu” i nie zużywała tablica całkowicie. Spróbuj
Drew Reese
111
var size = 10; var arrayOfArrays = [];
for (var i=0; i<bigarray.length; i+=size) {
     arrayOfArrays.push(bigarray.slice(i,i+size));
}
console.log(arrayOfArrays);

W przeciwieństwie splice(), slice()jest nieinwazyjne do oryginalnej tablicy.

Blazemonger
źródło
1
to rozwiązanie jest lepsze
Maduekwe Pedro
38

Po prostu zapętl tablicę, łącząc ją, aż zostanie zużyta.



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

while (a.length > 0) {

  chunk = a.splice(0,3)

  console.log(chunk)

}

wynik


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

Claudio
źródło
33

Możesz skorzystać z lodash: https://lodash.com/docs

_.chunk(['a', 'b', 'c', 'd'], 2);
// → [['a', 'b'], ['c', 'd']]
Alexander Paramonov
źródło
13

Zakładając, że nie chcesz niszczyć oryginalnej tablicy, możesz użyć takiego kodu, aby podzielić długą tablicę na mniejsze tablice, które możesz następnie powtórzyć:

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
źródło
7

Array.reduce może być nieefektywne w przypadku dużych tablic, szczególnie w przypadku operatora mod. Myślę, że czystszym (i prawdopodobnie łatwiejszym do odczytania) rozwiązaniem funkcjonalnym byłoby to:

const chunkArray = (arr, size) =>
  arr.length > size
    ? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)]
    : [arr];
tawnos178
źródło
6

Kolejna realizacja:

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 - To nie zmienia oryginalnej tablicy.

Lub, jeśli wolisz funkcjonalną, w 100% niezmienną (chociaż nie ma nic złego w mutowaniu w miejscu, jak to zrobiono powyżej) i samodzielną metodą:

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

Jako dodatek do użytkownika @ jyore odpowiedź , aw przypadku nadal chcesz zachować oryginalną tablicę:

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
źródło
4

Chciałbym również podzielić się moim rozwiązaniem. Jest trochę bardziej szczegółowy, ale też działa.

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

Wyjście (sformatowane):

[ [ 1,  2,  3,  4],
  [ 5,  6,  7,  8],
  [ 9, 10, 11, 12],
  [13, 14, 15    ] ]
Filipe Nicoli
źródło
3

Inna metoda:

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

Nie ma to wpływu na oryginalną tablicę, ponieważ kopia utworzona przy użyciu plasterka jest przekazywana do argumentu „this” mapy.

AFurlepa
źródło
2

Kolejna implementacja, wykorzystująca Array.reduce (myślę, że to jedyna brakująca!):

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

Jak wiele rozwiązań powyżej, ten jest nieniszczący. Zwracanie pustej tablicy, gdy rozmiar wynosi 0, to tylko konwencja. Jeśli ifblok zostanie pominięty, pojawi się błąd, który może być tym, czego chcesz.

Alf
źródło
1

Możesz spojrzeć na ten kod. Prosty i skuteczny.

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
źródło
1

Oto prosta jedna wkładka

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
źródło
1

Bardziej kompaktowy:

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
źródło
0

Jeśli potrzebujesz metody, która nie modyfikuje istniejącej tablicy, spróbuj tego:

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
źródło
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
źródło
nie zapomnij zrobić: newArr = [] zmienną lokalną
zgthompson
Odpowiedzi zawierające tylko kod są zwykle oznaczane, a następnie usuwane z powodu niskiej jakości. Czy mógłbyś skomentować, jak to rozwiązuje pierwotny problem?
Graham,
to nie działa, jeśli rozmiar porcji jest mniejszy niż rozmiar tablicy wejściowej.
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
źródło
2
Witamy w stackoverflow. Twoja odpowiedź poprawiłaby się, gdybyśmy dodali jakieś wyjaśnienie.
Simon.SA
0

jako funkcja

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

używać

arrayChunk(originalArray, 10) //10 being the chunk size.
Clint
źródło
0

używając rekurencji

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

Uwaga: istniejąca tablica, tj. MyArr, zostanie zmodyfikowana.

Siddharth Yadav
źródło
0

używając prototypu możemy ustawić bezpośrednio na klasę tablicową

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
źródło
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));  
  }

wyjście dla zakresu 3

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

wyjście dla zakresu 4

splittedArray === [[1,2,3,4][5,6,7,8][9,10,11]]
Haures Bogdan
źródło
Czy mógłbyś dodać opis?
ego