Diziyi parçalara ayır


516

Diyelim ki aşağıdaki gibi bir Javascript dizisi var:

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

Diyelim ki en fazla 10 element içeren diziyi daha küçük dizilere yığınlamak (bölmek) için hangi yaklaşım uygun olur?




24
İçin lodash kullanıcılar, sizin aradığınız _.chunk .
Ulysse BN

2
Sadece const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []güzel ve kısa olanı denedim ama @ AymKdn'in 1.000 elemente cevabı olduğu sürece 256 × ve 10.000 elemente kadar 1.058 × sürdüğü görülüyor!
Toph

son yığının minimum boyutuna da ihtiyacınız varsa, seçenekler şunlardır: stackoverflow.com/questions/57908133/…
Ahmet Çetin

Yanıtlar:


640

Array.slice yöntemi orijinal diziyi değiştirmeden, istenilen her türlü amaçlarla bir dizinin başlayan ortasına veya sonuna bir dilim elde edebilirsiniz.

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

19
Bunun chunkvarlığa karşı savunmak için bir fayda işlevi olup olmadığını hatırlayın 0. (sonsuz döngü)
Steven Lu

19
Hayır, son yığın diğerlerinden daha küçük olmalıdır.
Blazemonger

7
@Blazemonger, gerçekten! Bir dahaki sefere sonuçlara atlamadan önce kendim deneyeceğim. Ben (yanlış) dizi sınırlarını aşan array.slice içine bir girdi geçen bir sorun olacağını, ancak sadece mükemmel çalışıyor kabul!
rysqui

55
Biri gömlekleri (zincir severler) için : const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));.
Константин Ван

8
Neden j'ye ihtiyacınız var? Öncelikle bunun bir optimizasyon olduğunu düşündüm, ancak aslında (i = 0; i <array.length; i ++) {}
Alex

149

Dbaseman tarafından bir cevaptan değiştirildi: 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]]


küçük zeyilname :

Yukarıda belirtmek gerekir ki, o kadar zarif (bence) bir geçici çözüm kullanmaktır Array.map. Temel olarak aşağıdakileri yapar, burada ~ birleşimdir:

[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]

Aşağıdaki yöntemle aynı asimptotik çalışma süresine sahiptir, ancak boş listelerin oluşturulması nedeniyle belki de daha kötü bir sabit faktördür. Biri bunu şu şekilde yeniden yazabilir (çoğunlukla Blazemonger'ın yöntemiyle aynı, bu yüzden bu cevabı başlangıçta göndermedim):

Daha verimli yöntem:

// refresh page if experimenting and you already defined Array.prototype.chunk

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(chunkSize) {
    var R = [];
    for (var i = 0; i < this.length; i += chunkSize)
      R.push(this.slice(i, i + chunkSize));
    return R;
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk(3)
)


Bugünlerde tercih ettiğim yol yukarıdakilerden biri veya aşağıdakilerden biri:

Array.range = function(n) {
  // Array.range(5) --> [0,1,2,3,4]
  return Array.apply(null,Array(n)).map((x,i) => i)
};

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(n) {

    // ACTUAL CODE FOR CHUNKING ARRAY:
    return Array.range(Math.ceil(this.length/n)).map((x,i) => this.slice(i*n,i*n+n));

  }
});

Demo:

> JSON.stringify( Array.range(10).chunk(3) );
[[1,2,3],[4,5,6],[7,8,9],[10]]

Veya bir Array.range işlevi istemiyorsanız, aslında sadece bir astar (kabartmak hariç):

var ceil = Math.ceil;

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array(ceil(this.length/n)).fill().map((_,i) => this.slice(i*n,i*n+n));
}});

veya

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});

41
Eh, chunkdizideki işlevi çağırmaktan aldığınız serinlik hissi, eklediğiniz ekstra karmaşıklıktan ve yerleşik prototiplerle uğraşmanın neden olabileceği ince hatalardan daha ağır basmadığı için prototiple uğraşmaktan kaçınırım .
Gordon Gustafson

12
Onlarla uğraşmıyor, diziler için genişletiyor. Asla Object.prototype dokunmadan anlıyorum çünkü bu tüm nesnelere (her şeye) yayılacaktı ama bu Array'a özgü fonksiyon için herhangi bir sorun görmüyorum.
rlemon

Oldukça emin olmalıdır array.map(function(i)değil array.map(function(elem,i)olsa
Nigel Melek

3
Mozilla dev sitesindeki uyumluluk çizelgesine dayanarak, IE9 + için Array.map. Dikkatli ol.
Maikel D

Yüzmeyi geçmek için dikkatli olun - 7.5 tip sayı - öngörülemeyen parçalara yol açın
Gal Bracha

103

İşte azaltma kullanan bir ES6 sürümü

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

Dönüşümleri daha fazla haritalamaya / azaltmaya hazırsınız. Giriş diziniz olduğu gibi bırakıldı


Daha kısa ama daha az okunabilir bir sürümü tercih ederseniz concat, aynı sonuç için karışıma biraz serpebilirsiniz :

inputArray.reduce((all,one,i) => {
   const ch = Math.floor(i/perChunk); 
   all[ch] = [].concat((all[ch]||[]),one); 
   return all
}, [])

Bu en yoğun çözüm gibi görünüyor. ChunkIndex = Math.floor (index / perChunk) ne elde ediyor? Ortalama mı?
me-me

5/2 = 2.5ve Math.floor(2.5) = 2böylece indeks 5 ile öğe kova 2'ye yerleştirilecektir
Andrei R

Teşekkürler Andrei R. Ah böylece 0 - 2 arasında adımlar. Peki buna Matematik açısından ne denir? Demek istediğim, her dilim indeksini almak için her endeksi / 2 indeksini bölmeyi hiç düşünmemiştim. Bu yüzden başımı etrafına sarmaya çalışıyorum çünkü gerçekten hoşuma gidiyor ama Matematik terimleriyle tam olarak anlamıyorum. Genellikle toplam bir sayının ortalamasını almak için yapıyorum ama bu farklı görünüyor.
me-me

Bu çözüm diğer çözümlerle karşılaştırıldığında verimsizdir, çünkü her öğeyi yinelemeniz gerekir.
JP de la Torre

haklısın @JPdelaTorre, muhtemelen dizileri dilimleyen çözümler kadar verimli değil, ama saçları buraya ayırıyorsun. listelenen cevapların çoğu bu tanım tarafından verimsiz olacaktır.
Andrei R

102

Kodunuzu kimin kullanacağını bilmiyorsanız (3. taraflar, iş arkadaşları, daha sonraki bir tarihte kendiniz vb.) Array.prototype dahil yerel prototiplerle uğraşmaktan kaçının.

Prototipleri güvenli bir şekilde genişletmenin yolları vardır (ancak tüm tarayıcılarda değil) ve genişletilmiş prototiplerden oluşturulan nesneleri güvenli bir şekilde tüketmenin yolları vardır, ancak daha iyi bir kural En Az Sürpriz İlkesini takip etmek ve bu uygulamalardan tamamen kaçınmaktır.

Biraz zamanınız varsa, bu konu hakkında iyi bir tartışma için Andrew Dupont'un JSConf 2011 "Her Şeye İzin Verilir : Yerleşikleri Genişletme" konusundaki konuşmasını izleyin .

Ancak soruya geri dönersek, yukarıdaki çözümler işe yarayacak olsa da, aşırı karmaşıktırlar ve gereksiz hesaplama yükü gerektirirler. İşte benim çözümüm:

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;

25
"doğal prototipler ile mucking önlemek" yeni js geliştiriciler bu ifade geçici, kalıcı olmasa da dövme almalıdır.
Jacob Dalton,

2
Javascript'i yıllardır kullanıyorum ve prototiple uğraşmak için hiçbir zaman harcamıyorum, en çağıran fonksiyonlarda, bazı insanların yaptığınız gibi asla değişmiyor.
1984

2
gözlerimdeki en iyi öneri, anlaşılması en basit ve uygulamada çok teşekkür ederim!
Olga Farber

1
@JacobDalton Sanırım hepsi üniversitelerin hatası. İnsanlar OOP'un her yerde kullanılması gerektiğini düşünüyor. Yani "sadece bir işlev yaratmaktan" korkuyorlar. Bir şeyin içine koyduğundan emin olmak istiyorlar. Hiç uygun olmasa bile. Nokta gösterimi yoksa, "mimari" yoktur.
Gherman

51

Farklı cevapları jsperf.com'da test ettim. Sonuç burada mevcuttur: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds

Ve en hızlı işlev (ve IE8'den çalışır) şu şekildedir:

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

1
@AymKdn'e bu ölçütü yaptığınız için teşekkür ederiz: Bu çok yardımcı oldu! Splice yaklaşımını kullanıyordum ve Chrome v70 tarayıcımı 884432 boyutunda çöktü. Önerilen "dilim" yaklaşımınızla kodum artık tarayıcının "render" işlemini çökertmiyor. :)
Benny Neugebauer

34

Ekleme yöntemini kullanmayı tercih ederim :

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

16
Orijinal diziyi değiştirdiği için bu ekleme çözümüne dikkat etmelisiniz, bu nedenle yan etkileri açıkça belgelediğinizden emin olun.
bdrx

3
Sonra yerine dilim kullanın
mplungjan

@mplungjan Dilim kullanılırken sonuç tekrar tekrar aynı dizi olur. Bu yüzden, daha fazla değişiklik yapmadan bir bırakma yedeği değil.
nietonfir

Bu yanıta ekleyeceğim tek şey orijinal diziye bir klon . Bunu ES6'nın spread operatörü ile yapardım. var clone = [...array]daha sonra bu klonlanmış dizi üzerinde uzunluk kontrolü ve ekleme yapın.
MauricioLeal

1
Veya ES6 özelliklerini kullanamıyorsanız array = array.slice(), sığ bir kopya da oluşturabilirsiniz.
3limin4t0r

34

Tek astarlı in ECMA 6

const [list,chuckSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6]

new Array(Math.ceil(list.length / chuckSize)).fill().map(_ => list.splice(0,chuckSize))

9
orijinal listdiziyi değiştirir
Jacka

6
.Slice () ...map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
James Robey

2
JSPerf'de bu, diğer cevapların çoğundan çok daha fazla performans gösterir.
Micah Henning

30

Eski soru: Yeni cevap! Aslında bu sorunun cevabıyla çalışıyordum ve bir arkadaşımın bunu geliştirmesini istedim! İşte burada:

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

14
fyi, bu yöntemin performansı O (N ^ 2) 'dir, bu nedenle kodun performans açısından kritik bölümlerinde veya uzun dizilerde (özellikle dizinin .lengthyığın boyutundan çok daha büyük olduğu durumlarda n) kullanılmamalıdır. Bu tembel bir dil olsaydı (javascript'in aksine), bu algoritma O (N ^ 2) zamanından muzdarip olmazdı. Bununla birlikte, özyinelemeli uygulama zariftir. Muhtemelen ilk önce tekrar eden bir yardımcı işlev tanımlayıp array,positionsonra göndererek performansı iyileştirmek için değiştirebilirsiniz : Array.prototype.chunk[yardımcı işleviniz] döndürür (...)
ninjagecko

Bu gece chanelled olmalı ruhunu bana kutsama için teşekkürler sensai
ısırıldı

1
or ...var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
Ed Williams

28

Günümüzde daha küçük diziler halinde diziyi bölmek lodash' yığın işlevini kullanabilirsiniz https://lodash.com/docs#chunk artık döngüler ile keman gerek olmaz!


3
SO javascript soruları için feragat olması gerektiğini hissediyorum: lodash denediniz mi? Düğüme veya tarayıcıya eklediğim ilk şey.
Jacob Dalton

20

Birçok cevap var ama kullandığım şey bu:

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

İlk olarak, dizini yığın boyutuna bölerken kalan olup olmadığını kontrol edin.

Bir kalıntı varsa, sadece akümülatör dizisini döndürün.

Kalan yoksa, dizin yığın boyutuna bölünebilir, bu nedenle orijinal diziden (geçerli dizinden başlayarak) bir dilim alın ve bunu akümülatör dizisine ekleyin.

Yani, her azaltma yinelemesi için döndürülen akümülatör dizisi şöyle görünür:

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

Güzel çözüm ve iterasyonların güzel görsel temsili. Ben cevap olarak gönderdiğim çok benzer bir çözüm ile sona erdi: stackoverflow.com/a/60779547
mts knn

15

Jeneratörleri kullanma

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


3
Neredeyse jeneratör kullanan veya onları daha karmaşık şekillerde kullanan bu sorunun tüm cevaplarına şaşırdım. Bu çözüm ile güzel kısalık ve performans.
Keith

14

Tamam, oldukça sıkı biriyle başlayalım:

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

Hangi gibi kullanılır:

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

Sonra bu sıkı redüktör fonksiyonuna sahibiz:

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

Hangi gibi kullanılır:

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

Bir yavru kedi thisbir sayıya bağlandığımızda öldüğünden , bunun yerine manuel körük yapabiliriz:

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

Hangi gibi kullanılır:

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

Sonra hepsini bir seferde yapan hala oldukça sıkı bir işlev:

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

İE8'de Çalışmıyor.
Nadeemmnn Mohd

4
HA! yavru kedi yorumunu seviyorum. hiçbir ek yapıcı girdi için üzgünüm :)
29er

Ben yapacağını (p[i/n|0] || (p[i/n|0] = []))Bir değer atamak kalmamak gerekli değilse ...,
yckart

12

Saf ES6'da basit bir mutasyon geçirmeyen çözüm oluşturmayı amaçladım. Javascript özellikleri eşlemeden önce boş diziyi doldurmak için gerekli kılar :-(

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

Özyinelemeli bu sürüm daha basit ve daha çekici görünüyor:

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

ES6'nın gülünç zayıf dizi fonksiyonları iyi bulmacalar yapıyor :-)


1
Ben de böyle yazdım. Kaldırmak eğer hala çalışır 0dan fillyapar fillbiraz daha mantıklı bir görünüm, imho.
Coert Grobbelaar

12

Bu ES6 sözdizimi ile güzel bir özyinelemeli çözüm düşünüyorum:

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


9

Bu https://www.npmjs.com/package/array.chunk için bir npm paketi oluşturuldu

var result = [];

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

TypedArray kullanırken

var result = [];

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

@ A1rPun Kötü, orada yorum eklemedim. Evet, bunun için bir sliceyöntem yok TypedArray, subarraybunun yerine developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
zhiyelee

8

EcmaScript sürümü> = 5.1 chunk()kullanıyorsanız , O (N) karmaşıklığına sahip array.reduce () işlevinin işlevsel bir sürümünü uygulayabilirsiniz :

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

// nbrYukarıdakilerin her birinin açıklaması :

  1. Önceki değer, yani daha önce döndürülen parça dizisi boşsa veya son önceki parçada chunkSizeöğe varsa yeni bir parça oluşturun
  2. Yeni parçayı varolan parçalar dizisine ekleme
  3. Aksi takdirde, geçerli yığın, yığın dizisindeki son yığıntır
  4. Geçerli değeri parçaya ekle
  5. Değiştirilmiş parça dizisini döndürme
  6. Boş bir dizi geçirerek azaltmayı başlatın

Aşağıdakilere dayalı kurutma chunkSize:

var chunk3 = function(array) {
    return chunk(3, array);
};

console.log(chunk3(['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b', 'c' ], [ 'd', 'e' ] ]

chunk()İşlevi genel Arraynesneye ekleyebilirsiniz :

Object.defineProperty(Array.prototype, 'chunk', {
    value: function(chunkSize) {
        return this.reduce(function(previous, current) {
            var chunk;
            if (previous.length === 0 || 
                    previous[previous.length -1].length === chunkSize) {
                chunk = [];
                previous.push(chunk);
            }
            else {
                chunk = previous[previous.length -1];
            }
            chunk.push(current);
            return previous;
        }, []);
    }
});

console.log(['a', 'b', 'c', 'd', 'e'].chunk(4));
// prints [ [ 'a', 'b', 'c' 'd' ], [ 'e' ] ]


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

a. ek (0, 2), a'nın [0..1] alt dizisini a'dan kaldırır ve alt diziyi a [0..1] döndürür. Tüm bu dizilerin bir dizisini yapıyorum
Arpit Jain

2
Splice () yerine tahribatsız slice () yöntemini kullanmanızı öneririm
Ash Blue

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

1
Bunun neden aşağı oy verildiğinden emin değilim, ancak kod bazı açıklamaları kullanabilir.
jpaugh

2
Çünkü ekleme orijinal diziye zararlıdır.
metalim

7

Aşağıdaki ES2015 yaklaşımı, bir işlevi tanımlamak zorunda kalmadan ve doğrudan anonim diziler üzerinde çalışır (yığın boyutu 2 olan örnek):

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

Bunun için bir işlev tanımlamak istiyorsanız, aşağıdaki gibi yapabilirsiniz (K ._ 'nın Blazemonger'ın cevabı hakkındaki yorumunu geliştirerek ):

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

6

Ve bu konuya katkım olacaktı. Sanırım .reduce()en iyi yol bu.

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

Ancak yukarıdaki uygulama .reduce()tüm arrişlevlerden geçtiği için çok verimli değildir . Daha verimli bir yaklaşım (en hızlı zorunluluk çözümüne çok yakın), küçültülmüş (yığınlanacak) dizisi üzerinde yineleme yapmaktır, çünkü boyutunu önceden hesaplayabiliriz Math.ceil(arr/n);. Bir kez biz boş sonuç dizisi var gibi Array(Math.ceil(arr.length/n)).fill();geri kalanı arrdizinin dilimleri içine eşlemektir.

function chunk(arr,n){
  var r = Array(Math.ceil(arr.length/n)).fill();
  return r.map((e,i) => arr.slice(i*n, i*n+n));
}

arr = Array.from({length: 31},(_,i) => i+1);
res = chunk(arr,7);
console.log(JSON.stringify(res));


5

Lodash'tan yığın kullan

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

5

Kullanarak bir çözüm daha arr.reduce():

const chunk = (arr, size) => (
  arr.reduce((acc, _, i) => {
    if (i % size === 0) acc.push(arr.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)

Bu çözüm Steve Holgado'nun çözümüne çok benzer . Ancak, bu çözüm dizi yaymayı kullanmadığından ve redüktör işlevinde yeni diziler oluşturmadığından , diğer çözümden daha hızlıdır ( jsPerf testine bakın ) ve öznel olarak daha okunabilir (daha basit sözdizimi).

Her ninci yinelemede (burada n = size; ilk yinelemeden başlayarak), akümülatör dizisine ( acc), dizinin ( ) bir parçası eklenir arr.slice(i, i + size)ve sonra döndürülür. Diğer yinelemelerde, akümülatör dizisi olduğu gibi döndürülür.

Eğer sizesıfır, yöntem boş bir dizi döner. Eğer sizenegatif olup bu yöntemin sonucu verir kırık. Dolayısıyla, durumunuzda gerekiyorsa, negatif veya pozitif olmayan sizedeğerler hakkında bir şeyler yapmak isteyebilirsiniz .


Durumunuzda hız önemliyse, basit bir fordöngü kullanmaktan daha hızlı olacaktır arr.reduce()( jsPerf testine bakın ) ve bazıları bu stili daha okunabilir bulabilir:

function chunk(arr, size) {
  // This prevents infinite loops
  if (size < 1) throw new Error('Size must be positive')

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

4

Ramda kullanarak fonksiyonel bir çözüm için :

popularProductsGirdi diziniz nerede , 5yığın boyutu

import splitEvery from 'ramda/src/splitEvery'

splitEvery(5, popularProducts).map((chunk, i) => {
// do something with chunk

})


4

ES6 tek yönlü yaklaşım Array.prototype reduceve pushyöntemlere dayanmaktadır :

const doChunk = (list, size) => list.reduce((r, v) =>
  (!r.length || r[r.length - 1].length === size ?
    r.push([v]) : r[r.length - 1].push(v)) && r
, []);

console.log(doChunk([0,1,2,3,4,5,6,7,8,9,10,11,12], 5));
// [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12]]

4

ES6 Jeneratör sürümü

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

constBunun yerine kullanın .
Константин Ван

4

Bu, aklıma gelen en verimli ve kolay çözümdür:

function chunk(array, chunkSize) {
    let chunkCount = Math.ceil(array.length / chunkSize);
    let chunks = new Array(chunkCount);
    for(let i = 0, j = 0, k = chunkSize; i < chunkCount; ++i) {
        chunks[i] = array.slice(j, k);
        j = k;
        k += chunkSize;
    }
    return chunks;
}

4

ES6 işlevsel #ohmy #ftw yayılır

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


4

İşte kuyruk çağrı optimize olan özyinelemeli bir çözüm.

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


2

EDIT: @ mblase75 benim yazarken önceki cevabına daha özlü kod ekledi, bu yüzden onun çözüm ile devam öneririz.

Bunun gibi bir kod kullanabilirsiniz:

var longArray = ["Element 1","Element 2","Element 3", /*...*/];
var smallerArrays = []; // will contain the sub-arrays of 10 elements each
var arraySize = 10;
for (var i=0;i<Math.ceil(longArray.length/arraySize);i++) {
    smallerArrays.push(longArray.slice(i*arraySize,i*arraySize+arraySize));
}

arraySizeKüçük dizilerin maksimum uzunluğunu değiştirmek için değerini değiştirin.


2

İşte sadece özyineleme ve dilim () kullanan mutasyona uğramayan bir çözüm.

const splitToChunks = (arr, chunkSize, acc = []) => (
    arr.length > chunkSize ?
        splitToChunks(
            arr.slice(chunkSize),
            chunkSize,
            [...acc, arr.slice(0, chunkSize)]
        ) :
        [...acc, arr]
);

Sonra sadece splitToChunks([1, 2, 3, 4, 5], 3)almak gibi kullanın [[1, 2, 3], [4, 5]].

İşte denemeniz için bir keman: https://jsfiddle.net/6wtrbx6k/2/

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.