js将数组根据指定属性值分组成二维数组

本文介绍如何将给定的一维数组oneDimensionalArr按照multi、codeKey和codeType字段进行分组,形成每个组内具有相同multi、codeKey和codeType的子数组,便于数据管理和分析。

根据mulit字段+codeKey+codeType三个字段进行分组

oneDimensionalArr: [
     {multi: 'one',codeKey: 'LTL', codeType: 1, name: 'ABC', id: 1},
     {multi: 'one',codeKey: 'LTL', codeType: 1, name: 'ioh', id: 3},

     {multi: 'mulit',codeKey: 'LTL', codeType: 1, name: 'CDF', id: 6},

     {multi: 'mulit',codeKey: 'FES', codeType: 1, name: 'werr', id: 4},

     {multi: 'one',codeKey: 'FES', codeType: 2, name: 'ytg', id: 5},
     {multi: 'one',codeKey: 'FES', codeType: 2, name: 'CDF', id: 2},

     {multi: 'mulit',codeKey: 'FRE', codeType: 2, name: 'etery', id: 7},
     {multi: 'mulit',codeKey: 'FRE', codeType: 2, name: 'nvn', id: 8},
     {multi: 'mulit',codeKey: 'FRE', codeType: 2, name: 'abc', id: 9},

     {multi: 'one',codeKey: 'Small', codeType: 1, name: 'ware', id: 10},
     {multi: 'one',codeKey: 'Small', codeType: 1, name: 'trwe', id: 11},
]

最终想要的结果

[
      {
        multi: 'one',
        codeKey: 'LTL', 
        codeType: 1, 
        list:[
          {multi: 'one',codeKey: 'LTL', codeType: 1, name: 'ABC', id: 1},
          {multi: 'one',codeKey: 'LTL', codeType: 1, name: 'ioh', id: 3},
        ]
     },
     {
        multi: 'mulit',
        codeKey: 'LTL', 
        codeType: 1, 
        list:[{multi: 'mulit',codeKey: 'LTL', codeType: 1, name: 'CDF', id: 6}]
    },
    {
      multi: 'mulit',
      codeKey: 'FES', 
     codeType: 1, 
      list:[
            {multi: 'mulit',codeKey: 'FES', codeType: 1, name: 'werr', id: 4},
           ]
    },
    {
      multi: 'one',
      codeKey: 'FES', 
      codeType: 2, 
      list:[
             {multi: 'one',codeKey: 'FES', codeType: 2, name: 'ytg', id: 5},
              {multi: 'one',codeKey: 'FES', codeType: 2, name: 'CDF', id: 2},
          ]
  },
  {
     multi: 'mulit',
     codeKey: 'FRE', 
     codeType: 2, 
     list:[
            {multi: 'mulit',codeKey: 'FRE', codeType: 2, name: 'etery', id: 7},
            {multi: 'mulit',codeKey: 'FRE', codeType: 2, name: 'nvn', id: 8},
           {multi: 'mulit',codeKey: 'FRE', codeType: 2, name: 'abc', id: 9},
          ]
 },
{
    multi: 'one',
    codeKey: 'Small', 
    codeType: 1, 
    list:[
             {multi: 'one',codeKey: 'Small', codeType: 1, name: 'ware', id: 10},
             {multi: 'one',codeKey: 'Small', codeType: 1, name: 'trwe', id: 11},
         ]
 },

实现方案

// 根据指定属性值将一维数组进行分组成二维数组
mapTwoDimension(arr) {
      console.log(arr, 'arr');
      let dataArr = []
      if (arr.length === 0)  {
            return dataArr
      }
      arr.map(oneDim => {
           if (dataArr.length == 0) {
                dataArr.push({
                     multi: oneDim.multi,
                     codeKey: oneDim.codeKey,
                     codeType: oneDim.codeType,
                     list: [oneDim]
                })
            } else {
                let res = dataArr.some(item => { // 判断相同,有就添加到当前项
                if (item.multi == oneDim.multi && item.codeType == oneDim.codeType &&
                        item.codeKey == oneDim.codeKey) {
                        item.list.push(oneDim)
                        return true
                        }
                    })
                    if (!res) { // 如果没找相同添加一个新对象
                        dataArr.push({
                        multi: oneDim.multi,
                        codeKey: oneDim.codeKey,
                        codeType: oneDim.codeType,
                        list: [oneDim]
                        })
                    }
                 }
     })
     console.info(dataArr, 'dataArr')
     return dataArr
},

 

<think> 我们有一个需求:在JavaScript中,将一维数组数组元素为对象)根据相同的key值组,转换为二维数组(实际上是对象,因为组后的键是动态的,但每个键对应的值是数组)。注意,这里的组是指将具有相同键值的元素放入同一个数组中,并以该键值作为结果对象的键。 例如,输入数组: [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Charlie' } ] 根据'id'组后,我们期望得到: { 1: [ { id: 1, name: 'Alice' }, { id: 1, name: 'Charlie' } ], 2: [ { id: 2, name: 'Bob' } ] } 注意:输出结果是一个对象,而不是二维数组。因为键是动态的(这里是1和2),所以不能使用数组索引(0,1,...)来组织。但是,有时我们可能希望得到二维数组的形式(即只保留组后的数组,不要键),那么可以使用`Object.values(grouped)`来获得一个二维数组,其中每个子数组是同一组。 然而,根据用户需求,他们希望将一维数组根据相同的key值转换为二维数组,并且参考了引用[1]中的代码(使用reduce方法,按固定长度割),但我们的需求是按相同属性值组。 在JavaScript中,我们可以使用`Array.prototype.reduce`方法来实现组,类似于PHP中的方法。 步骤: 1. 初始化一个空对象(作为reduce的初始值)。 2. 遍历数组的每一个元素。 3. 对于每个元素,获取指定key的值(例如'id')。 4. 检查结果对象中是否已经有以该值为键的数组,如果没有则初始化为空数组。 5. 将当前元素添加到该键对应的数组中。 6. 最后,返回这个对象。 如果用户希望得到二维数组(即只包含组后的数组,不包含键),则再使用`Object.values()`将对象的值转换为数组。 但是,用户的问题是“转换为二维数组”,注意二维数组在JavaScript中就是数组数组,例如: [ [ { id: 1, name: 'Alice' }, { id: 1, name: 'Charlie' } ], [ { id: 2, name: 'Bob' } ] ] 但是这样我们丢失了组键(id值)。所以通常我们保留组键的对象形式更有用。不过,根据具体需求,我们可以提供两种结果。 参考引用[1]中的代码是按固定长度数组,与按属性值组不同。而引用[2]中的代码是查找数组元素下标,也不直接相关。 因此,我们按照按属性值组的需求来实现。 代码如下: 方案1:使用reduce方法组,得到一个以key为键,以数组为值的对象。 方案2:如果需要二维数组数组数组,不保留键),则使用Object.values()将上面对象的值转换为数组。 注意:如果组键是数字,那么结果对象的键也是数字(但实际上对象键会被转换为字符串,所以数字键在对象中也是字符串形式)。如果希望保持数字类型,可以在组时使用Map,最后再将Map转换为对象或者数组。 我们也可以使用Map来组,这样键的类型可以保持(但最终输出为对象时,键还是字符串)。如果希望输出二维数组并且不关心键,那么使用Map与否不重要。 下面给出两种实现方式: 方式一:使用reduce和普通对象 ```javascript function groupByKey(array, key) { return array.reduce((result, currentItem) => { const keyValue = currentItem[key]; // 如果result中还没有这个键,则初始化一个空数组 if (!result[keyValue]) { result[keyValue] = []; } // 将当前元素加入对应的数组 result[keyValue].push(currentItem); return result; }, {}); } ``` 方式二:使用Map(可以保持键的类型,但最终输出为对象时,键会变字符串。如果输出Map,则键保持原类型) ```javascript function groupByKey(array, key) { const map = new Map(); array.forEach(item => { const keyValue = item[key]; if (!map.has(keyValue)) { map.set(keyValue, []); } map.get(keyValue).push(item); }); // 将Map转换为对象(键为字符串) return Object.fromEntries(map.entries()); // 或者直接返回Map,但这样后续处理可能需要使用Map的方法 } ``` 如果我们需要二维数组(不保留键),则: ```javascript function groupByKeyToArray(array, key) { const grouped = groupByKey(array, key); // 先得到对象 return Object.values(grouped); } ``` 示例: ```javascript const input = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Charlie' }, { id: 3, name: 'David' } ]; const groupedObject = groupByKey(input, 'id'); console.log(groupedObject); // 输出: // { // '1': [ { id: 1, name: 'Alice' }, { id: 1, name: 'Charlie' } ], // '2': [ { id: 2, name: 'Bob' } ], // '3': [ { id: 3, name: 'David' } ] // } const groupedArray = groupByKeyToArray(input, 'id'); console.log(groupedArray); // 输出: // [ // [ { id: 1, name: 'Alice' }, { id: 1, name: 'Charlie' } ], // [ { id: 2, name: 'Bob' } ], // [ { id: 3, name: 'David' } ] // ] ``` 注意:使用`Object.values`得到的数组顺序是对象键的插入顺序。在ES6中,对象的属性顺序是:数字键(按升序排列)-> 字符串键(按插入顺序)-> Symbol键(按插入顺序)。但是,在我们的例子中,我们使用的是数字键,但是它们在对象中会被转换为字符串。然而,在ES6规范中,数字键(即使是字符串形式)也会按照数字大小升序排列,但请注意,这仅针对数字字符串键(如'1','2')有效,如果键是混合类型(比如既有数字字符串又有普通字符串),那么顺序是先数字字符串升序,再其他字符串插入顺序。 在我们的组函数中,由于我们使用reduce(或forEach)遍历数组,所以键出现的顺序就是我们在数组中遇到的顺序(除了数字键会被排序?)。但实际上,根据规范,对于非数字字符串键,顺序是插入顺序;对于数字字符串键,会按照数值升序排列。因此,为了避免混淆,如果顺序很重要,我们可以使用Map,因为Map会保持插入顺序(包括键的插入顺序),然后使用`Array.from(map.values())`来得到二维数组数组数组,按组键的首次出现顺序排列)。 因此,如果我们希望组后的二维数组的顺序是按照组键在数组中第一次出现的顺序,那么我们可以使用Map来组,然后取Map的值(Map.values())并转换为数组。 修改后的`groupByKeyToArray`函数(保持顺序): ```javascript function groupByKeyToArray(array, key) { const map = new Map(); array.forEach(item => { const keyValue = item[key]; if (!map.has(keyValue)) { map.set(keyValue, []); } map.get(keyValue).push(item); }); return Array.from(map.values()); } ``` 这样,组后的数组顺序就是组键在数组中第一次出现的顺序。例如: 输入数组: [ { id: 2, ... }, { id: 1, ... }, { id: 2, ... } ] 组后的二维数组顺序: 第一个子数组是id为2的组(因为2先出现),第二个子数组是id为1的组。 总结: 1. 根据相同key组,通常得到一个对象(键为组值,值为数组)。 2. 如果只需要二维数组数组数组),则提取对象的值(Object.values)或者使用Map并取values。 3. 使用Map可以保证组顺序(按组键首次出现的顺序)。 因此,我们根据需求选择不同的输出形式。 下面是完整的代码示例: </think> ### JavaScript实现一维数组根据相同Key值组为二维数组的方法 在JavaScript中,根据相同Key值将一维数组组为二维数组(实际是对象结构)是常见的数据处理需求。下面详细介绍实现方法和代码示例: #### 核心实现方法 使用`Array.prototype.reduce()`方法是最简洁高效的实现方式: ```javascript function groupByKey(array, key) { return array.reduce((result, currentItem) => { const keyValue = currentItem[key]; // 若该Key值不存在则初始化空数组 if (!result[keyValue]) { result[keyValue] = []; } // 将当前元素添加到对应Key的数组中 result[keyValue].push(currentItem); return result; }, {}); } ``` #### 代码说明 1. **输入参数**: - `array`:原始一维数组,元素为对象 - `key`:用于组的属性名(如"id") 2. **处理流程**: - 初始化空对象`{}`作为累加器 - 遍历数组元素,提取当前元素的Key值 - 若结果对象中无此Key,则创建空数组 - 将当前元素推入对应Key的数组 - 返回组后的对象 3. **时间复杂度**:$O(n)$,其中$n$为数组长度 #### 使用示例 ```javascript // 原始数据 const input = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Charlie' }, { id: 3, name: 'David' } ]; // 按id组 const grouped = groupByKey(input, 'id'); console.log(grouped); /* 输出: { 1: [ { id: 1, name: 'Alice' }, { id: 1, name: 'Charlie' } ], 2: [{ id: 2, name: 'Bob' }], 3: [{ id: 3, name: 'David' }] } */ ``` #### 转换为纯二维数组 如果需要标准的二维数组(非对象结构),可添加后续处理: ```javascript const twoDArray = Object.values(grouped); console.log(twoDArray); /* 输出: [ [ { id: 1, name: 'Alice' }, { id: 1, name: 'Charlie' } ], [{ id: 2, name: 'Bob' }], [{ id: 3, name: 'David' }] ] */ ``` #### 方案对比 | 方法 | 优点 | 缺点 | |--------------------|--------------------------|--------------------------| | `reduce()` | 代码简洁,一次遍历完 | 需要理解累加器机制 | | `forEach()`+对象 | 逻辑直观 | 需额外声明临时变量 | | Lodash的`groupBy` | 最简语法(需引入外部库) | 增加项目依赖 | #### 注意事项 1. **Key值处理**:当Key值为数字时,会自动转为字符串(JavaScript对象键的特性) 2. **空值处理**:建议添加空值检查`if (!currentItem[key])` 3. **大数据优化**:超过10万条数据时,建议使用Map替代对象提高性能[^1] ```javascript // 使用Map的优化版本 function groupByMap(array, key) { const map = new Map(); array.forEach(item => { const keyVal = item[key]; if (!map.has(keyVal)) map.set(keyVal, []); map.get(keyVal).push(item); }); return Object.fromEntries(map); } ``` #### 实际应用场景 1. 商品按分类组显示 2. 日志数据按日期聚合 3. 用户消息按会话组 4. 统计报表数据按维度汇总
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值