V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
xiaohupro
V2EX  ›  JavaScript

JavaScript 中指定大小分割数组的一种实现

  •  
  •   xiaohupro · 233 天前 · 1668 次点击
    这是一个创建于 233 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天分享一个使用 JavaScript 分割数组为多个自数组的方法实现。我使用它的场景如下:

    给定一个数组 arr 和指定大小 fixed:

    const arr = [
    	{
    		id: 1,
    		name: 'name1'
    	},
    	{
    		id: 2,
    		name: 'name2'
    	},
    	{
    		id: 3,
    		name: 'name3'
    	},
    	{
    		id: 4,
    		name: 'name4'
    	},
    	{
    		id: 5,
    		name: 'name5'
    	},
    	{
    		id: 6,
    		name: 'name6'
    	},
    	{
    		id: 7,
    		name: 'name7'
    	},
    	{
    		id: 8,
    		name: 'name8'
    	},
    	{
    		id: 9,
    		name: 'name9'
    	}
    ]
    const fixed = 2;
    

    期望的结果是生成一个数组,数组中包含 5 个数组,如下:

    [
      [ { id: 1, name: 'name1' }, { id: 2, name: 'name2' } ],
      [ { id: 3, name: 'name3' }, { id: 4, name: 'name4' } ],
      [ { id: 3, name: 'name3' }, { id: 6, name: 'name6' } ],
      [ { id: 3, name: 'name3' }, { id: 6, name: 'name6' } ],
      [ { id: 3, name: 'name3' }, {} ]
    ]
    

    按照 fixed 的大小分割,如果遇到不够 fixed 大小的,使用空对象填充。这种场景对表格数据填充需要等宽或者等数量会有所帮助。 具体实现代码如下:

    /**
     *
     * @param {arr} 要分割的数组
     * @param {fixed} 指定分割的大小
     **/
    function splitArr(arr, fixed) {
    	let result = [];
    	let size = arr.length;
    	let len = Math.ceil(arr.length / fixed);//向上取整
    	for(let i=0; i<len; i++){
    		let tempArr = [];
    		for(let j=0; j<fixed; j++){
    			if((i*fixed)+j >= size){
    				tempArr[j] = {}
    			}else{
    				tempArr[j] = arr[j];
    			}
    		}
    		result.push(tempArr);
    		if(arr.length > 0){
    			arr.splice(i, fixed);
    		}
    	}
    	return result;
    }
    
    const arr = [
    	{
    		id: 1,
    		name: 'name1'
    	},
    	{
    		id: 2,
    		name: 'name2'
    	},
    	{
    		id: 3,
    		name: 'name3'
    	},
    	{
    		id: 4,
    		name: 'name4'
    	},
    	{
    		id: 5,
    		name: 'name5'
    	},
    	{
    		id: 6,
    		name: 'name6'
    	},
    	{
    		id: 7,
    		name: 'name7'
    	},
    	{
    		id: 8,
    		name: 'name8'
    	},
    	{
    		id: 9,
    		name: 'name9'
    	}
    ]
    
    const result = splitArr(arr, 2);
    
    console.log(result);
    

    希望本次分享的代码对你有所帮助,Thanks !!!

    第 1 条附言  ·  233 天前
    果然还是人多力量大呀,发现了好多写法,感谢大家
    第 2 条附言  ·  233 天前
    实现上还是有问题
    第 3 条附言  ·  233 天前
    上面代码中在进行 splice 的时候应该将 arr.splice(i, fixed) 改为 arr.splice(0, fixed)。不然会出现问题
    第 4 条附言  ·  232 天前
    经过大家的回复我最终选择使用 loadsh 的 _chunk 方法实现,的确,使用 loadsh 可以很快速的实现,对于我的需求,通过 _chunk 方法分块后再将最后一个块不满 fixed 等填充慢即可。再次感谢大家的分享
    20 条回复    2024-08-26 21:51:18 +08:00
    StrangerA
        1
    StrangerA  
       233 天前
    为什么例子里分割后 id 为 3 的出现了 4 次,为 6 的出现了两次?
    xjngbla
        2
    xjngbla  
       233 天前
    没什么用,但是谢谢你
    hay313955795
        3
    hay313955795  
       233 天前
    function splitArr(arr, fixed) {
    var index = 0;
    var arrayLength = arr.length;
    var result = [];
    for (index = 0; index < arrayLength; index += fixed) {
    var tempArr = arr.slice(index, index+fixed);
    if(tempArr.length<fixed){
    tempArr.splice(tempArr.length+1, 0, ...new Array(fixed-tempArr.length).fill({}));
    }
    result.push(tempArr);
    }

    return result;
    }
    var result = splitArr([{name:'1'},{name:'2'},{name:'3'},{name:'4'},{name:'5'},{name:'6'},{name:'7'},{name:'8'},{name:'9'}], 4);
    console.log(result);

    我的只有一个 for 循环。。
    StrangerA
        4
    StrangerA  
       233 天前
    ```
    import { groupBy } from 'lodash'

    const arr = ...

    const fixed = 2

    const group = groupBy(arr, (item) => Math.floor((item['id'] + 1) / fixed))
    const newArr = Object.values(group).map((item) =>
    new Array(fixed).fill({}).map((_, index) => item[index] || {}),
    )

    console.log(newArr)
    ```

    执行结果:

    ```
    [
    [ { id: 1, name: 'name1' }, { id: 2, name: 'name2' } ],
    [ { id: 3, name: 'name3' }, { id: 4, name: 'name4' } ],
    [ { id: 5, name: 'name5' }, { id: 6, name: 'name6' } ],
    [ { id: 7, name: 'name7' }, { id: 8, name: 'name8' } ],
    [ { id: 9, name: 'name9' }, {} ]
    ]
    ```

    op 你要的是这样的吗
    YorkWong
        5
    YorkWong  
       233 天前
    之前写过一个将数组 array 分割成多个长度为 chunkSize 的子数组

    splitArray(array, chunkSize = 500) {
    const result = [];
    const length = array.length;

    for (let i = 0; i < length; i += chunkSize) {
    result.push(array.slice(i, i + chunkSize));
    }

    return result;
    },
    Leviathann
        6
    Leviathann  
       233 天前
    reduce 一下就行了
    vvhy
        7
    vvhy  
       233 天前
    ```
    reshape = (a,dim,i=0,d=0)=>dim[d] ? Array(dim[d]).fill().map((_,j)=>reshape(a, dim, i * dim[d] + j, d + 1)) : a[i];
    reshape([...Array(24).keys()], [2,3,4])
    // [[[0,1,2,3],[4,5,6,7],[8,9,10,11]],[[12,13,14,15],[16,17,18,19],[20,21,22,23]]]
    ```
    xiaohupro
        8
    xiaohupro  
    OP
       233 天前
    @StrangerA 是的,学到了,还有这种操作,没用过 lodash 这个库,完了去学习学习
    iyiluo
        9
    iyiluo  
       233 天前
    先把数组填充到可以整除的倍数,然后直接分割就行了
    kneo
        11
    kneo  
       233 天前
    逻辑问题就不说了,自己修去。提一个要注意的地方:返回新数组就不要修改原数组。
    xiaohupro
        13
    xiaohupro  
    OP
       233 天前
    @StrangerA 感谢提醒,刚刚看了一下,应该将 splice(i, fixed) 改为 splice(0, fixed),因为每次删除时候应该从头开始,手残了,抱歉
    xiaohupro
        14
    xiaohupro  
    OP
       233 天前
    @StrangerA 感谢提醒, 逻辑上有点问题,已 append
    xiaohupro
        15
    xiaohupro  
    OP
       233 天前
    @kneo 逻辑上 splice 那里确实出了问题,已 append ,感谢。这种写法确实修改了原始数组,不是太好
    StrangerA
        16
    StrangerA  
       233 天前
    @huhailong1121 lodash 提供那些功能在某些语言里都是标准库能提供的存在了。简单的数组操作安心用 lodash 就成,不要浪费时间手搓,把省下来的时间用来写更重要的东西(甚至用来摸鱼都比手搓浪费时间强)
    otakustay
        17
    otakustay  
       233 天前
    @StrangerA #4 你都 lodash 了,不直接用 chunk
    StrangerA
        18
    StrangerA  
       233 天前
    @otakustay 学艺不精,感谢指点
    otakustay
        19
    otakustay  
       233 天前
    GPT 整出来的:

    function chunk(array, size) {
    return Array.from({ length: Math.ceil(array.length / size) }, (_, index) =>
    array.slice(index * size, index * size + size)
    );
    }
    forty
        20
    forty  
       122 天前
    let n = arr.length, f = fixed, pad = {};
    let result = new Array(Math.ceil(n/f)).fill(0).map((_,i)
    =>arr.slice(i*f,i*f+f).concat(new Array(i*f+f>n?fixed-n%fixed:0).fill(pad)));

    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5312 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 05:48 · PVG 13:48 · LAX 21:48 · JFK 00:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.