js数据的处理,如何将数组字典归类重新组合?

// 原始数据

const data = [{
    type: '政治',
    area:  '朝阳',
    num: 10
},{
    type: 金融',
    area:  '朝阳',
    num: 20
},{
    type: 贸易',
    area:  '海淀',
    num: 200
},{
    type: 政治',
    area:  '海淀',
    num: 200
},{
    type: 信息',
    area:  '海淀',
    num: 100
}]

// 处理之后的数据

tableData: [{
    area: '朝阳',
    '政治': 10,
    '金融': 20,
    '贸易': 0,
    '信息': 0,
    sum: 30 // 所有维度的和
    }, {
    area: '海淀',
    '政治': 200,
    '金融': 0,
    '贸易': 200,
    '信息': 100,
    sum: 500
]

最终的表格,我用excel画的😳
image.png

阅读 2.4k
4 个回答

你这个处理数据有点特别,看结果数据要求的是没出现的属性也要算出0来。

刚开始我想的是完成收集和合计:

function generate(data){
    const map = {};
    // 遍历数据
    data.forEach(item=>{
        // 如果已经存在对应地区的数据
        if(map[item.area]){
            // 把数据塞进去
            map[item.area].push(item)
        }else{
            // 初始化一个数据并塞入数据
            map[item.area] = [item]
        }
    })
    // 遍历map
    return Object.keys(map).map(area=>{
        const list = map[area]
        const obj = {area: area, sum:0}
        // 遍历数组,算出合计
        list.forEach(item=>{
            obj[item.type] = item.num
            obj.sum+=item.num
        })
        return obj
    })
}

如果原数据能保证所有地区的所有属性都有值,这样就解决了。但如果无法保证的话,那只能换一种方式,姑且认为原数据出现的属性就是所有属性了,那就是第一次遍历的时候就要汇总所有属性。

function generate2(data){
    const map = {};
    // 收集所有出现的属性
    const attrs = {};
    data.forEach(item=>{
        attrs[item.type] = 1;
        if(map[item.area]){
            map[item.area][item.type] = item.num;
        }else{
            map[item.area] = {}
            map[item.area][item.type] = item.num;
        }
    })
    return Object.keys(map).map(area=>{
        const areaMap = map[area]
        const obj = {area: area, sum:0}
        Object.keys(attrs).forEach(key=>{
            obj[key] = areaMap[key]??0
            obj.sum+= obj[key]
        })
        return obj
    })
}
const data = [
    { type: "政治", area: "朝阳", num: 10 },
    { type: "金融", area: "朝阳", num: 20 },
    { type: "贸易", area: "海淀", num: 200 },
    { type: "政治", area: "海淀", num: 200 },
    { type: "信息", area: "海淀", num: 100 }
];

// 既然要补足属性,先把所有字段找出来
const fields = [... new Set(data.map(({ type }) => type))];

// 合并信息,根据 area 把 type 作为属性合并成对象(分组)
const merged = data.reduce((acc, it) => {
    const { type, area, num } = it;
    (
        // 如果 acc[area] 不存在,创建一个所有属性为 0 的初始对象
        acc[area] ??= Object.fromEntries(fields.map(field => [field, 0]))
    )[type] = num;
    return acc;
}, {});

// 分组后是 { area => props } 的形式,把 area 合并到 props 中,形成数组
const result = Object.entries(merged).map(([area, it]) => ({ area, ...it }));
console.log(result);

在初始化对象的时候,也可以直接把 area 加进去,这样最后就不需要作合并处理,直接 Object.values() 把值集取出来就行

// ....
        acc[area] ??= {
            area,
            ...Object.fromEntries(fields.map(field => [field, 0]))
        }
// ....
const result = Object.values(merged);
// ....

甚至可以直接在取到 fields 之就后创建一个原型对象出来:

const fields = [... new Set(data.map(({ type }) => type))];
const prototype = Object.fromEntries(fields.map(field => [field, 0]));

//... 后面 reduce 中的处理直接从原型生成新对象
(acc[area] ??= { area, ...prototype })[type] = num;

简单好理解的处理方法:

const sort = (list) => {
    const areas = [...new Set(list.map(r => r.area))];
    const types = list.reduce((t, x) => ({...t, [x.type]: 0}), {});
    const res = [];
    areas.forEach(area => {
        const row = {area: area, ...types, sum: 0};
        list.forEach(r => {
            if (r.area !== area) return;
            row[r.type] += r.num;
            row.sum += r.num;
        })
        res.push(row);
    })
    return res;
}

console.log(sort(data));
let dict = new Set()
let arr = data.reduce((acc, item) => {
  dict.add(item.type)
  let findRes = acc.find(list => list.area === item.area)

  if (findRes) {
    findRes[item.type] = item.num
  } else {
    acc.push({
      area: item.area,
      [item.type]: item.num
    })
  }

  return acc

}, [])

arr.forEach(item => {
  let sum = 0

  dict.forEach(key => {
    let val = item[key]
    item[key] = val || 0
    sum += val || 0
  })
  item.sum = sum
})

so easy 啊

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题