-
Notifications
You must be signed in to change notification settings - Fork 1.4k
chunky monkey
S1ngS1ng edited this page Mar 21, 2017
·
1 revision
- 这个
function接收两个参数,第一个参数为数组arr,即为需要分割的原数组。第二个参数为数字size,表示分割后每段的长度。返回值为分割后形成的二维数组 - 比如接收的是
[1, 2, 3, 4, 5, 6]与2,那么输出就是[[1, 2], [3, 4], [5, 6]] - 需要注意的是,如果分割的过程出现剩余,那么返回值的最后一个数组会比较短。比如接收的是
[1, 2, 3]与2,那么输出就是[[1, 2], [3]]
- 对于基本解法,我们先不用数组内建方法,只通过最基本的循环来实现,因此,你只需要知道
for循环和push就够了 - Array.push()
- 只需要模拟一下执行过程,就知道我们只需要写一个循环,实现先取出数组的
0到size位,然后给两个值都加上size,也就是取出size到size + size位,直到数组终点。这样,每次截取的长度都是size - 因此,需要嵌套循环。外层的循环用于确定范围,内层的循环就是把范围内的元素每个都
push到临时数组中,再在内层循环结束后把生成的数组push到结果中就可以了 - 写的时候需要注意,一定要判断边界。否则你会得到
undefined - 这个思路其实就是双指针,请先试着自己写一下,再看答案
function chunk(arr, size) {
// 这个数组用于存储结果
var result = [];
for (var i = 0; i < arr.length; i += size) {
// 这个数组用于存储临时的数组片段
var temp = [];
for (var j = i; j < i + size; j++) {
// 判断边界。可以思考一下,为什么不能写成 if (arr[j])
if (j < arr.length) {
temp.push(arr[j]);
}
}
result.push(temp);
}
return result;
}- 整体思路应该不难理解。外层的
i用于确定截取的起始点。内层的j就是在i与i + size之间,读出每一个元素,并存储到temp中。每存好一个片段 (即内层循环结束),就把temp保存到result中 - 这个思路的关键在于选对
i和j的初始值以及循环过程中增值。既然我们需要实现每size个元素为一个片段,那么我们肯定需要确定每次截取的起点和终点 - 我们用
i来表示截取的起点,那么不难得出i的初始值为 0。增值应该为size。跳出条件也很简单,只要i < arr.length,我们就可以一直执行 - 用
j来选取范围中的元素,因此j的初始值应该就为i(注意,这个i是会变化的)。至于j的结束值,那么应该为i + size。因为我们需要截取的是从i到i + size的元素。j的增值显然应该为j++,因为我们需要获取这个范围之内的所有元素 - 既然我们设置了
j是从i到i + size,那么就需要处理i + size超出数组长度的情况。简单考虑下这个例子,传入数组[1, 2, 3, 4, 5],size为4,那么我们应该得到[[1, 2, 3, 4], [5]]。当i为 0 的时候没有问题,但当第二次循环,即i为 4 的时候,这时j也为 4。而内层循环跳出条件,i + size为 8,显然超出了原数组的长度。如果我们读取arr[6],会得到undefined,显然我们不想把这个结果放进temp - 那么如何判断呢?你可能第一反应是用
if (arr[j])来判断。可以先试试,结果是通不过测试的。原因在于 JavaScript 的隐式类型转换,if()中的内容会被转换成Boolean,相当于执行的是if(Boolean(arr[j]))或者说if(!!arr[j])。那么如果arr[j]是 0,就也会返回 false。但其实,0在数组中肯定是允许的情况,我们不应该把它排除掉 - 因此,这里我们只需要简单地判断
j是否超出了arr.length即可。也就有了上面的代码
我知道,上面解释的内容有点多,看起来好像很复杂。但其实,自己写一写就知道了,这个思路是最容易想出来的
- 没错,上面我们就是造了一个
.slice()的轮子 u.u
- 之所以推荐用
slice,是因为就算第二个参数超出了数组的长度也没有关系,不会产生undefined之类的问题 - 基本答案中,
j那一层循环的代码,其实就是.slice()。我们来用slice替换掉那部分吧
function chunk(arr, size) {
var result = [];
// 设置起点
var i = 0;
while (i < arr.length) {
result.push(arr.slice(i, i + size));
i += size;
}
return result;
}- 用
while写循环要注意什么?一定不要忘了写i += size。否则就是无限循环了。另外,记得要先给i设置一个初始值 0 - 由于
.slice()返回截取后的数组,因此我们直接push就可以了。给一个数组push一个数组,就会形成二维数组。顺便,如果你想生成一维数组,请用.concat() - 这个方法看起来简洁很多了。当然,还有更简洁的写法
-
.splice()是为数不多的,会直接改变原数组的数组方法。我们可以通过.splice()来删除数组中的元素,返回值又恰好是被删除的数组部分。具体语法请参考下面的链接
function chunk(arr, size) {
var result = [];
while (arr.length) {
result.push(arr.splice(0, size));
}
return result;
}-
splice方法可以接收两个参数,第一个是起始点,第二个是需要删除的长度。后面还可以再加参数,表示删除后需要在当前位置添加的元素 - 既然
splice返回的是被删除部分,我们直接push到result就好了 - 至于循环的跳出条件,由于
splice会删元素,因此数组长度会改变。而数组长度不可能为负数,只能为非负整数。所以,当长度为 0 的时候,我们就可以跳出了。因此就有了上面的写法