Array splitsen in brokken

Stel dat ik een Javascript-array heb die er als volgt uitziet:

["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.

Welke aanpak zou geschikt zijn om de array in veel kleinere arrays op te delen (op te splitsen) met, laten we zeggen, maximaal 10 elementen?


Antwoord 1, autoriteit 100%

De array.slicemethode kan een segment extraheren uit het begin, het midden of het einde van een array voor welke doeleinden dan ook, zonder de originele array te wijzigen.

var i,j, temporary, chunk = 10;
for (i = 0,j = array.length; i < j; i += chunk) {
    temporary = array.slice(i, i + chunk);
    // do whatever
}

Antwoord 2, autoriteit 20%

Aangepast van een antwoord door dbaseman: https://stackoverflow.com/a/10456344/711085

Object.defineProperty(Array.prototype, 'chunk_inefficient', {
  value: function(chunkSize) {
    var array = this;
    return [].concat.apply([],
      array.map(function(elem, i) {
        return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
      })
    );
  }
});
console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk_inefficient(3)
)
// [[1, 2, 3], [4, 5, 6], [7]]

Antwoord 3, autoriteit 19%

Hier is een ES6-versie met gebruik van reduce

var perChunk = 2 // items per chunk    
var inputArray = ['a','b','c','d','e']
var result = inputArray.reduce((resultArray, item, index) => { 
  const chunkIndex = Math.floor(index/perChunk)
  if(!resultArray[chunkIndex]) {
    resultArray[chunkIndex] = [] // start a new chunk
  }
  resultArray[chunkIndex].push(item)
  return resultArray
}, [])
console.log(result); // result: [['a','b'], ['c','d'], ['e']]

Antwoord 4, autoriteit 15%

Probeer te voorkomen dat u gaat rommelen met native prototypes, waaronder Array.prototype, als u niet weet wie uw code zal gebruiken (3e partijen, collega’s, uzelf op een later tijdstip, enz.) .

Er zijn manieren om prototypes veilig uit te breiden (maar niet in alle browsers) en er zijn manieren om objecten die zijn gemaakt op basis van uitgebreide prototypen veilig te gebruiken, maar een betere vuistregel is om de Principe van de minste verrassingen vermijd deze praktijken helemaal.

Als je wat tijd hebt, bekijk dan de JSConf 2011 talk van Andrew Dupont, “Alles is toegestaan: ingebouwde ingebouwde functies uitbreiden”, voor een goede discussie over dit onderwerp.

Maar terug naar de vraag, hoewel de bovenstaande oplossingen zullen werken, zijn ze te complex en vereisen ze onnodige rekenkundige overhead. Hier is mijn oplossing:

function chunk (arr, len) {
  var chunks = [],
      i = 0,
      n = arr.length;
  while (i < n) {
    chunks.push(arr.slice(i, i += len));
  }
  return chunks;
}
// Optionally, you can do the following to avoid cluttering the global namespace:
Array.chunk = chunk;

Antwoord 5, autoriteit 9%

Ik heb de verschillende antwoorden getest op jsperf.com. Het resultaat is daar beschikbaar: https://web.archive .org/web/20150909134228/https://jsperf.com/chunk-mtds

En de snelste functie (en die werkt vanuit IE8) is deze:

function chunk(arr, chunkSize) {
  if (chunkSize <= 0) throw "Invalid chunk size";
  var R = [];
  for (var i=0,len=arr.length; i<len; i+=chunkSize)
    R.push(arr.slice(i,i+chunkSize));
  return R;
}

Antwoord 6, autoriteit 8%

One-liner in ECMA 6

const [list,chunkSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6]
[...Array(Math.ceil(list.length / chunkSize))].map(_ => list.splice(0,chunkSize))

Antwoord 7, autoriteit 5%

Generatoren gebruiken

function* chunks(arr, n) {
  for (let i = 0; i < arr.length; i += n) {
    yield arr.slice(i, i + n);
  }
}
let someArray = [0,1,2,3,4,5,6,7,8,9]
console.log([...chunks(someArray, 2)]) // [[0,1],[2,3],[4,5],[6,7],[8,9]]

Antwoord 8, autoriteit 5%

Ik gebruik liever splicemethode:

var chunks = function(array, size) {
  var results = [];
  while (array.length) {
    results.push(array.splice(0, size));
  }
  return results;
};

Antwoord 9, Autoriteit 4%

Tegenwoordig kun je Lodash ‘Chunk-functie gebruiken om de array te splitsen in kleinere arrays https://lodash.com/docs#chunkNiet nodig om meer met de lussen te viemen!


Antwoord 10, Autoriteit 4%

Oude vraag: Nieuw antwoord! Ik werkte eigenlijk met een antwoord van deze vraag en had het een vriend om het te verbeteren! Dus hier is het:

Array.prototype.chunk = function ( n ) {
    if ( !this.length ) {
        return [];
    }
    return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};
[1,2,3,4,5,6,7,8,9,0].chunk(3);
> [[1,2,3],[4,5,6],[7,8,9],[0]]

Antwoord 11, Autoriteit 3%

Er zijn veel antwoorden geweest, maar dit is wat ik gebruik:

const chunk = (arr, size) =>
  arr
    .reduce((acc, _, i) =>
      (i % size)
        ? acc
        : [...acc, arr.slice(i, i + size)]
    , [])
// USAGE
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
chunk(numbers, 3)
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Controleer eerst op een rest bij het verdelen van de index door de brokgrootte.

Als er een rest is, retourneer dan de Accumulator-array.

Als er geen rest is, is de index deelbaar door de brokgrootte, dus neem een ​​slice van de originele array (beginnend bij de huidige index) en voeg deze toe aan de Accumulator-array.

Dus de geretourneerde accumulatorarray voor elke iteratie van het verminderen ziet er zoiets uit:

// 0: [[1, 2, 3]]
// 1: [[1, 2, 3]]
// 2: [[1, 2, 3]]
// 3: [[1, 2, 3], [4, 5, 6]]
// 4: [[1, 2, 3], [4, 5, 6]]
// 5: [[1, 2, 3], [4, 5, 6]]
// 6: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 7: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 8: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 9: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Antwoord 12, Autoriteit 3%

Ik denk dat dit een mooie recursieve oplossing is met ES6-syntaxis:

const chunk = function(array, size) {
  if (!array.length) {
    return [];
  }
  const head = array.slice(0, size);
  const tail = array.slice(size);
  return [head, ...chunk(tail, size)];
};
console.log(chunk([1,2,3], 2));

Antwoord 13, Autoriteit 2%

Nog een oplossing met Array.prototype.reduce():

const chunk = (array, size) =>
  array.reduce((acc, _, i) => {
    if (i % size === 0) acc.push(array.slice(i, i + size))
    return acc
  }, [])
// Usage:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const chunked = chunk(numbers, 3)
console.log(chunked)

Antwoord 14, Autoriteit 2%

OK, laten we beginnen met een vrij strakke:

function chunk(arr, n) {
    return arr.slice(0,(arr.length+n-1)/n|0).
           map(function(c,i) { return arr.slice(n*i,n*i+n); });
}

Wat als volgt wordt gebruikt:

chunk([1,2,3,4,5,6,7], 2);

Dan hebben we deze strakke verloopfunctie:

function chunker(p, c, i) {
    (p[i/this|0] = p[i/this|0] || []).push(c);
    return p;
}

Wat als volgt wordt gebruikt:

[1,2,3,4,5,6,7].reduce(chunker.bind(3),[]);

Aangezien een kitten sterft wanneer we thisaan een getal binden, kunnen we in plaats daarvan handmatig curryen als volgt doen:

// Fluent alternative API without prototype hacks.
function chunker(n) {
   return function(p, c, i) {
       (p[i/n|0] = p[i/n|0] || []).push(c);
       return p;
   };
}

Wat als volgt wordt gebruikt:

[1,2,3,4,5,6,7].reduce(chunker(3),[]);

Dan de nog steeds vrij strakke functie die het allemaal in één keer doet:

function chunk(arr, n) {
    return arr.reduce(function(p, cur, i) {
        (p[i/n|0] = p[i/n|0] || []).push(cur);
        return p;
    },[]);
}
chunk([1,2,3,4,5,6,7], 3);

Antwoord 15, autoriteit 2%

Ik was gericht op het creëren van een eenvoudige niet-muterende oplossing in pure ES6. Eigenaardigheden in javascript maken het noodzakelijk om de lege array te vullen voordat deze wordt toegewezen 🙁

function chunk(a, l) { 
    return new Array(Math.ceil(a.length / l)).fill(0)
        .map((_, n) => a.slice(n*l, n*l + l)); 
}

Deze versie met recursie lijken eenvoudiger en meer dwingend:

function chunk(a, l) { 
    if (a.length == 0) return []; 
    else return [a.slice(0, l)].concat(chunk(a.slice(l), l)); 
}

De belachelijk zwakke matrixfuncties van ES6 zorgt voor goede puzzels: -)


Antwoord 16, Autoriteit 2%

one-liner

const chunk = (a,n)=>[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(n*i,n+n*i));

Voor typoscript

const chunk = <T>(arr: T[], size: number): T[][] =>
  [...Array(Math.ceil(arr.length / size))].map((_, i) =>
    arr.slice(size * i, size + size * i)
  );

DEMO

const chunk = (a,n)=>[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(n*i,n+n*i));
document.write(JSON.stringify(chunk([1, 2, 3, 4], 2)));

Antwoord 17

Gemaakt op een NPM pakket voor dit https://www.npmjs.com/package/array .chunk

var result = [];
for (var i = 0; i < arr.length; i += size) {
  result.push(arr.slice(i, size + i));
}
return result;

Bij gebruik van een typedarray

var result = [];
for (var i = 0; i < arr.length; i += size) {
  result.push(arr.subarray(i, size + i));
}
return result;

Antwoord 18

results = []
chunk_size = 10
while(array.length > 0){
   results.push(array.splice(0, chunk_size))
}

Antwoord 19

Als u Ecmascript-versie & GT; = 5.1 gebruikt, kunt u een functionele versie van chunk()implementeren met array.reduce () die O (n) complexiteit heeft:

function chunk(chunkSize, array) {
    return array.reduce(function(previous, current) {
        var chunk;
        if (previous.length === 0 || 
                previous[previous.length -1].length === chunkSize) {
            chunk = [];   // 1
            previous.push(chunk);   // 2
        }
        else {
            chunk = previous[previous.length -1];   // 3
        }
        chunk.push(current);   // 4
        return previous;   // 5
    }, []);   // 6
}
console.log(chunk(2, ['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b' ], [ 'c', 'd' ], [ 'e' ] ]

Antwoord 20

De volgende ES2015-aanpak werkt zonder een functie en direct op anonieme arrays te hoeven definiëren (voorbeeld met Chunk Maat 2):

[11,22,33,44,55].map((_, i, all) => all.slice(2*i, 2*i+2)).filter(x=>x.length)

Als u hiervoor een functie hiervoor wilt definiëren, kunt u het als volgt doen (verbetering van K._ ‘s commentaar op Blazemonger’s antwoord ):

const array_chunks = (array, chunk_size) => array
    .map((_, i, all) => all.slice(i*chunk_size, (i+1)*chunk_size))
    .filter(x => x.length)

Antwoord 21

met Array.prototype.splice()en splice het totdat de array element heeft.

Array.prototype.chunk = function(size) {
    let result = [];
    while(this.length) {
        result.push(this.splice(0, size));
    }
    return result;
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.chunk(2));

Antwoord 22

in coffeescript:
b = (a.splice(0, len) while a.length)
demo 
a = [1, 2, 3, 4, 5, 6, 7]
b = (a.splice(0, 2) while a.length)
[ [ 1, 2 ],
  [ 3, 4 ],
  [ 5, 6 ],
  [ 7 ] ]

Antwoord 23

Gebruik chunk van laagash

lodash.chunk(arr,<size>).forEach(chunk=>{
  console.log(chunk);
})

Antwoord 24

De One Line in Pure JavaScript:

function chunks(array, size) {
  return Array.apply(0,{length: Math.ceil(array.length / size)}).map((_, index) => array.slice(index*size, (index+1)*size))
}
// The following will group letters of the alphabet by 4
console.log(chunks([...Array(26)].map((x,i)=>String.fromCharCode(i + 97)), 4))

Antwoord 25

Hier is een voorbeeld waar ik een array in stukken van 2 elementen splitst, gewoon door chunks uit de array te splitsen totdat de originele array leeg is.

   const array = [86,133,87,133,88,133,89,133,90,133];
    const new_array = [];
    const chunksize = 2;
    while (array.length) {
        const chunk = array.splice(0,chunksize);
        new_array.push(chunk);
    }
    console.log(new_array)

Antwoord 26

En dit zou mijn bijdrage aan dit onderwerp zijn. Ik denk dat .reduce()de beste manier is.

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);
        res = segment(arr,7);
console.log(JSON.stringify(res));

Antwoord 27

ES6 spreidt functionele #ohmy #ftw

const chunk =
  (size, xs) => 
    xs.reduce(
      (segments, _, index) =>
        index % size === 0 
          ? [...segments, xs.slice(index, index + size)] 
          : segments, 
      []
    );
console.log( chunk(3, [1, 2, 3, 4, 5, 6, 7, 8]) );

Antwoord 28

Voor een functionele oplossing, gebruik Ramda:

Waar popularProductsuw invoerarray is, is 5de brokgrootte

import splitEvery from 'ramda/src/splitEvery'
splitEvery(5, popularProducts).map((chunk, i) => {
// do something with chunk
})

Antwoord 29

ES6 Generator-versie

function* chunkArray(array,size=1){
    var clone = array.slice(0);
    while (clone.length>0) 
      yield clone.splice(0,size); 
};
var a = new Array(100).fill().map((x,index)=>index);
for(const c of chunkArray(a,10)) 
    console.log(c);

Antwoord 30

Hier is een recursieve oplossing die tail call-optimalisatie is.

const splitEvery = (n, xs, y=[]) =>
  xs.length===0 ? y : splitEvery(n, xs.slice(n), y.concat([xs.slice(0, n)])) 
console.log(splitEvery(2, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))

Other episodes