[javascript] 배열을 청크로 나누기

다음과 같은 Javascript 배열이 있다고 가정 해 봅시다.

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

예를 들어 최대 10 개의 요소를 사용하여 배열을 여러 개의 작은 배열로 청크 (분할)하는 데 어떤 접근법이 적합합니까?



답변

array.slice의 방법은 원래의 배열을 변경하지 않고, 당신이 요구하는 어떤 목적을 위해 배열의 시작, 중간 또는 끝에서 조각을 추출 할 수 있습니다.

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


답변

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


작은 부록 :

위의 내용은 사용하기에 우아하지 않은 (내 마음에) 해결 방법이라는 것을 지적해야합니다 Array.map. 기본적으로 다음을 수행합니다. 여기서 ~는 연결입니다.

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

아래 방법과 동일한 점근 적 실행 시간을 갖지만 빈 목록을 작성하기 때문에 더 나쁜 상수 요인 일 수 있습니다. 이것을 다음과 같이 다시 작성할 수 있습니다 (대부분 Blazemonger의 방법과 동일하므로 원래이 답변을 제출하지 않은 이유입니다).

보다 효율적인 방법 :

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


요즘 가장 선호하는 방법은 위 또는 다음 중 하나입니다.

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

  }
});

데모:

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

또는 Array.range 함수를 원하지 않으면 실제로는 하나의 라이너 (플러 프 제외)입니다.

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

또는

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


답변

다음은 reduce를 사용하는 ES6 버전입니다.

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

그리고 추가 맵 / 축소 변환을 연결할 준비가되었습니다. 입력 배열이 그대로 남아 있습니다


더 짧지 만 읽기 어려운 버전을 선호하는 경우 concat동일한 최종 결과를 위해 일부 를 믹스에 뿌릴 수 있습니다.

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


답변

누가 코드를 사용할지 모르는 경우 (타사, 동료, 나중에 자신 등) Array.prototype을 포함한 기본 프로토 타입을 사용하지 않도록하십시오.

프로토 타입을 안전하게 확장 할 수있는 방법이 있지만 (모든 브라우저가 아님) 확장 된 프로토 타입에서 생성 된 객체를 안전하게 소비 할 수있는 방법이 있지만 가장 좋은 방법 은 최소한의 놀람 원칙 을 따르고 이러한 방법을 모두 피하는 것입니다.

시간이 있다면 Andrew Dupont의 JSConf 2011 강연에서 “모든 것이 허용됨 : 내장 기능 확장”을 보고이 주제에 대한 좋은 토론을하십시오.

그러나 질문으로 돌아 가면 위의 솔루션은 작동하지만 지나치게 복잡하고 불필요한 계산 오버 헤드가 필요합니다. 내 해결책은 다음과 같습니다.

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;


답변

jsperf.com에 대한 다른 답변을 테스트했습니다. 결과는 https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds에서 확인할 수 있습니다.

그리고 가장 빠른 기능은 IE8에서 작동합니다.

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


답변

스플 라이스 방법 을 사용하고 싶습니다 .

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


답변

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