想象一下,我有一个像这样的JS数组:
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
我想要的是将该数组拆分为N个较小的数组。例如:
split_list_in_n(a, 2)
[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11]]
For N = 3:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]
For N = 4:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]
For N = 5:
[[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]
对于Python,我有这个:
def split_list_in_n(l, cols):
""" Split up a list in n lists evenly size chuncks """
start = 0
for i in xrange(cols):
stop = start + len(l[i::cols])
yield l[start:stop]
start = stop
对于JS来说,我能想出的最好的解决方案是递归函数,但我不喜欢它,因为它复杂而丑陋。这个内部函数返回一个像这样的数组[1,2,3,null,4,5,6,null,7,8],然后我必须再次循环它并手动拆分它。 (我的第一次尝试是返回这个:[1,2,3,[4,5,6,[7,8,9]]],我决定使用空分隔符。)
function split(array, cols) {
if (cols==1) return array;
var size = Math.ceil(array.length / cols);
return array.slice(0, size).concat([null]).concat(split(array.slice(size), cols-1));
}
这是一个jsfiddle:http://jsfiddle.net/uduhH/
你会怎么做?谢谢!
答案 0 :(得分:117)
您可以使切片“平衡”(子阵列的长度尽可能少)或“偶数”(所有子阵列但最后一个具有相同的长度):
function chunkify(a, n, balanced) {
if (n < 2)
return [a];
var len = a.length,
out = [],
i = 0,
size;
if (len % n === 0) {
size = Math.floor(len / n);
while (i < len) {
out.push(a.slice(i, i += size));
}
}
else if (balanced) {
while (i < len) {
size = Math.ceil((len - i) / n--);
out.push(a.slice(i, i += size));
}
}
else {
n--;
size = Math.floor(len / n);
if (len % size === 0)
size--;
while (i < size * n) {
out.push(a.slice(i, i += size));
}
out.push(a.slice(size * n));
}
return out;
}
///////////////////////
onload = function () {
function $(x) {
return document.getElementById(x);
}
function calc() {
var s = +$('s').value, a = [];
while (s--)
a.unshift(s);
var n = +$('n').value;
$('b').textContent = JSON.stringify(chunkify(a, n, true))
$('e').textContent = JSON.stringify(chunkify(a, n, false))
}
$('s').addEventListener('input', calc);
$('n').addEventListener('input', calc);
calc();
}
<p>slice <input type="number" value="20" id="s"> items into
<input type="number" value="6" id="n"> chunks:</p>
<pre id="b"></pre>
<pre id="e"></pre>
答案 1 :(得分:8)
我刚刚对算法进行了迭代实现:http://jsfiddle.net/ht22q/。它会通过您的测试用例。
function splitUp(arr, n) {
var rest = arr.length % n, // how much to divide
restUsed = rest, // to keep track of the division over the elements
partLength = Math.floor(arr.length / n),
result = [];
for(var i = 0; i < arr.length; i += partLength) {
var end = partLength + i,
add = false;
if(rest !== 0 && restUsed) { // should add one element for the division
end++;
restUsed--; // we've used one division element now
add = true;
}
result.push(arr.slice(i, end)); // part of the array
if(add) {
i++; // also increment i in the case we added an extra element for division
}
}
return result;
}
答案 2 :(得分:7)
function split(arr, n) {
var res = [];
while (arr.length) {
res.push(arr.splice(0, n));
}
return res;
}
&#13;
答案 3 :(得分:5)
我认为使用拼接的这种方式最干净:
splitToChunks(array, parts) {
let result = [];
for (let i = parts; i > 0; i--) {
result.push(array.splice(0, Math.ceil(array.length / i)));
}
return result;
}
例如,对于parts = 3
,您将获得剩余部分的1/3,然后是1/2,然后是数组的其余部分。 Math.ceil
确保在元素数量不均匀的情况下,它们将排到最早的块。
(注意:这会破坏初始数组。)
答案 4 :(得分:5)
您可以将其缩小为矩阵。下面的示例将数组(arr
)拆分为两个位置数组的矩阵。如果您想要其他尺寸,只需更改第二行的2值:
target.reduce((memo, value, index) => {
if (index % 2 == 0 && index !== 0) memo.push([])
memo[memo.length - 1].push(value)
return memo
}, [[]])
希望它有所帮助!
编辑:因为有些人还在评论,因为我正在修复每个块的大小而不是我想要的块数,因此无法回答这个问题。这里是代码,解释了我在评论部分中要解释的内容:使用target.length
。
// Chunk function
const chunk = (target, size) => {
return target.reduce((memo, value, index) => {
// Here it comes the only difference
if (index % (target.length / size) == 0 && index !== 0) memo.push([])
memo[memo.length - 1].push(value)
return memo
}, [[]])
}
// Usage
write(chunk([1, 2, 3, 4], 2))
write(chunk([1, 2, 3, 4], 4))
// For rendering pruposes. Ignore
function write (content) { document.write(JSON.stringify(content), '</br>') }
答案 5 :(得分:3)
老问题,但由于vanillaJS不是一个要求,并且很多人试图用lodash / chunk解决这个问题,并且没有误解_.chunk
实际做了什么,这里是使用lodash
的简洁+准确的解决方案:
(与接受的答案不同,即使originalArray.length
&lt; numCols
}
import _chunk from 'lodash/chunk'
/**
* Split an array into n subarrays (or columns)
* @param {Array} flatArray Doesn't necessarily have to be flat, but this func only works 1 level deep
* @param {Number} numCols The desired number of columns
* @return {Array}
*/
export function splitArray(flatArray, numCols){
const maxColLength = Math.ceil(flatArray.length/numCols)
const nestedArray = _chunk(flatArray, maxColLength)
let newArray = []
for (var i = 0; i < numCols; i++) {
newArray[i] = nestedArray[i] || []
}
return newArray
}
最后的for
循环可以保证所需的“列数”。
答案 6 :(得分:2)
递归方法,未经测试。
function splitArray(array, parts, out) {
var
len = array.length
, partLen
if (parts < len) {
partLen = Math.ceil(len / parts);
out.push(array.slice(0, partLen));
if (parts > 1) {
splitArray(array.slice(partLen), parts - 1, out);
}
} else {
out.push(array);
}
}
答案 7 :(得分:2)
另一个递归工作很好,它不那么难看
function nSmaller(num, arr, sliced) {
var mySliced = sliced || [];
if(num === 0) {
return sliced;
}
var len = arr.length,
point = Math.ceil(len/num),
nextArr = arr.slice(point);
mySliced.push(arr.slice(0, point));
nSmaller(num-1, nextArr, mySliced);
return(mySliced);
}
答案 8 :(得分:1)
function splitArray(arr, numOfParts = 10){
const splitedArray = []
for (let i = 0; i < numOfParts;i++) {
const numOfItemsToSplice = arr.length / 10;
splitedArray.push(arr.splice(0, numOfItemsToSplice))
}
return splitedArray;
}
答案 9 :(得分:1)
通常来讲,静音是Bad Thing™。
这很好,干净而且有幂等。
function partition(list = [], n = 1) {
const isPositiveInteger = Number.isSafeInteger(n) && n > 0;
if (!isPositiveInteger) {
throw new RangeError('n must be a positive integer');
}
const partitions = [];
const partitionLength = Math.ceil(list.length / n);
for (let i = 0; i < list.length; i += partitionLength) {
const partition = list.slice(i, i+partitionLength);
partitions.push( partition );
}
return partitions;
}
答案 10 :(得分:1)
您可以使用简单的递归函数
const chunkify = (limit, completeArray, finalArray = [])=>{
if(!completeArray.length) return finalArray
const a = completeArray.splice(0,limit);
return chunkify(limit, completeArray, [...finalArray,a])
}
答案 11 :(得分:1)
可能更清洁的方法如下(不使用任何其他库):
var myArray = [];
for(var i=0; i<100; i++){
myArray.push(i+1);
}
console.log(myArray);
function chunk(arr, size){
var chunkedArr = [];
var noOfChunks = Math.ceil(arr.length/size);
console.log(noOfChunks);
for(var i=0; i<noOfChunks; i++){
chunkedArr.push(arr.slice(i*size, (i+1)*size));
}
return chunkedArr;
}
var chunkedArr = chunk(myArray, 3);
console.log(chunkedArr);
我创建了自己的数组,这个数组是分块的。您可以找到代码here
我们还有一种方法&#34; chunk&#34;在lodash图书馆,这是非常有用的。希望有所帮助
答案 12 :(得分:0)
我这样做了,它有效......
function splitArray(array, parts) {
if (parts< array.length && array.length > 1 && array != null) {
var newArray = [];
var counter1 = 0;
var counter2 = 0;
while (counter1 < parts) {
newArray.push([]);
counter1 += 1;
}
for (var i = 0; i < array.length; i++) {
newArray[counter2++].push(array[i]);
if (counter2 > parts - 1)
counter2 = 0;
}
return newArray;
} else
return array;
}
答案 13 :(得分:0)
如果您可以使用lodash
并希望采用函数式编程方法,那么我就会提出以下建议:
const _ = require('lodash')
function splitArray(array, numChunks) {
return _.reduce(_.range(numChunks), ({array, result, numChunks}, chunkIndex) => {
const numItems = Math.ceil(array.length / numChunks)
const items = _.take(array, numItems)
result.push(items)
return {
array: _.drop(array, numItems),
result,
numChunks: numChunks - 1
}
}, {
array,
result: [],
numChunks
}).result
}
答案 14 :(得分:0)
以上所有方法都可以正常工作,但是如果你有associative
数组,字符串作为键呢?
objectKeys = Object.keys;
arraySplit(arr, n) {
let counter = 0;
for (const a of this.objectKeys(arr)) {
this.arr[(counter%n)][a] = arr[a];
counter++;
}
}
答案 15 :(得分:0)
只需使用lodash'chunk函数将数组拆分为更小的数组https://lodash.com/docs#chunk不再需要使用循环!
答案 16 :(得分:0)
我有一个不会改变原始数组的
IsKinematic
答案 17 :(得分:0)
如果您碰巧事先知道想要的块的大小,则可以使用一种非常优雅的ES6方法:
const groupsOfFour = ([a,b,c,d, ...etc]) =>
etc.length? [[a,b,c,d], groupsOfFour(etc)] : [[a,b,c,d]];
console.log(groupsOfFour([1,2,3,4,1,2,3,4,1,2,3,4]));
我发现这种表示法非常有用,例如从Uint8ClampedArray
中解析出RGBA。
答案 18 :(得分:0)
如果你知道想设置child_arrays.length那么我认为这个解决方案最好:
<input type="file" id="i_file" name="Img" value="" />
拨打fn: sp(2,[1,2,3,4,5,6,7,8,9,10,11])// 2 - child_arrat.length
答案: [1,2],[3,4],[5,6],[7,8],[9,10],[11]
答案 19 :(得分:0)
splitToChunks(arrayvar, parts) {
let result = [];
for (let i = parts; i > 0; i--) {
result.push(arrayvar.splice(0, Math.ceil(arrayvar.length / i)));
}
return result;
}
答案 20 :(得分:0)
检查我的这个数组拆分版本
// divide array
Array.prototype.divideIt = function(d){
if(this.length <= d) return this;
var arr = this,
hold = [],
ref = -1;
for(var i = 0; i < arr.length; i++){
if(i % d === 0){
ref++;
}
if(typeof hold[ref] === 'undefined'){
hold[ref] = [];
}
hold[ref].push(arr[i]);
}
return hold;
};
答案 21 :(得分:-1)
function parseToPages(elements, pageSize = 8) {
var result = [];
while (elements.length) {
result.push(elements.splice(0, pageSize));
}
return result;
}
答案 22 :(得分:-2)
lodash chunk(array, Math.round(array.length / n))
答案 23 :(得分:-3)
如果你正在使用lodash,你可以很容易地实现它,如下所示:
import {chunk} from 'lodash';
// divides the array into 2 sections
chunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 2); // => [[1,2,3,4,5,6], [7,8,9,10,11]]