js数组对象格式变更

怎么样把下面这个对象数组变成所需的格式:
1.根据toolName进行合并将
2.将timeRange做合并为一个数组
3.将value合并成一个数组(timeRange和value要对应,即:月份和数量对应)

//原格式
payload = [
    {
        toolName: "手机",
        normName: "营销量",
        timeRange: "2021-11",
        value: 145
    },
    {
        toolName: "手机",
        normName: "营销额",
        timeRange: "2021-11",
        value: 6
    },
    {
        toolName: "平板",
        normName: "营销量",
        timeRange: "2021-11",
        value: 10
    },
    {
        toolName: "平板",
        normName: "营销额",
        timeRange: "2021-11",
        value: 1354.64
    },
    {
        toolName: "电脑",
        normName: "营销量",
        timeRange: "2021-11",
        value: 1000
    },
    {
        toolName: "手机",
        normName: "营销量",
        timeRange: "2021-12",
        value: 42
    },
    {
        toolName: "手机",
        normName: "营销额",
        timeRange: "2021-12",
        value: 60
    },
    {
        toolName: "平板",
        normName: "营销量",
        timeRange: "2021-12",
        value: 8
    },
    {
        toolName: "平板",
        normName: "营销额",
        timeRange: "2021-12",
        value: 1200
    },
    {
        toolName: "电脑",
        normName: "营销量",
        timeRange: "2021-12",
        value: 872
    }
]
//所需格式
 [
    {
        "手机":[
            {
                normName: "营销量",
                timeRange: ["2021-11",'2021-12'],
                value: [145,42]
            },
            {
                normName: "营销额",
                timeRange: ["2021-11",'2021-12'],
                value: [6,60]
            }
        ]
    },
    {
        "平板":[
            {
                normName: "营销量",
                timeRange: ["2021-11",'2021-12'],
                value: [10,8]
            },
            {
                normName: "营销额",
                timeRange: ["2021-11",'2021-12'],
                value: [1354.64,1200]
            }
        ]
    },
    {
        "电脑":[
            {
                normName: "营销量",
                timeRange: ["2021-11",'2021-12'],
                value: [1000,872]
            }
        ]
    },
]
阅读 3k
4 个回答
function exchange(list) {
  const objByToolName = list.reduce((res,v) => {
    (res[v.toolName] ||= []).push(v);
    return res;
  }, {});
  return Object.entries(objByToolName).map(([key, values]) => ({
    [key]: Object.values(values.reduce((res, v) => {
      // 这里的reduce相当于在做一次合并,即objByNormName
      const item = res[v.normName] ||= {timeRange: [], value: [], normName: v.normName};
      item.timeRange.push(v.timeRange)
      item.value.push(v.value);
      return res;
    }, {}))
  }))
}
exchange(payload)
let payloadDeepMap = payload.reduce((acc,cur)=>{
    let toolNameMap = (acc[cur.toolName]||={});
    let normNameMap = (toolNameMap[cur.normName]||={});
    (normNameMap.timeRange||=[]).push(cur.timeRange);
    (normNameMap.value||=[]).push(cur.value);
    return acc;
},{});
console.log(payloadDeepMap);
let res = Object.entries(payloadDeepMap).reduce((acc,[toolName,obj])=>{
    Object.entries(obj).forEach(([normName,other])=>{
        (acc[toolName]||=[]).push({normName,...other});
    })
    return acc;
},{})
console.log(res);

第一次,归并所有字段。
第二次,解构成对应结果。
image.png

性能应该有点优化。

let payloadDeepMap = payload.reduce((acc,cur)=>{
    let toolNameMap = (acc[cur.toolName]||={});
    let normNameMap = (toolNameMap[cur.normName]||={});
    normNameMap.normName = cur.normName;
    (normNameMap.timeRange||=[]).push(cur.timeRange);
    (normNameMap.value||=[]).push(cur.value);
    return acc;
},{});
console.log(payloadDeepMap);
let res = Object.entries(payloadDeepMap).reduce((acc,[toolName,obj])=>{
    acc[toolName] = Object.values(obj);
    return acc;
},{})
console.log(res);

用 Lodash 不用自己造轮子,但性能不一定高

import _ from "lodash";

interface Node {
    toolName: string;
    normName: string;
    timeRange: string;
    value: number;
}

interface GrouptedNode {
    [key: string]: {
        normName: string;
        timeRange: string[];
        value: number[];
    }
}

function groupIt(data: Node[]): GrouptedNode {
    return _(data)
        .groupBy("toolName")
        .mapValues(topValues => _(topValues)
            .groupBy("normName")
            .map((nodes, normName) => ({
                normName,
                timeRange: nodes.map(node => node.timeRange),
                value: nodes.map(node => node.value)
            }))
            .value()
        )
        .value() as any;
}

如果手写,主要就是造个 groupBy 这个轮子。

测试代码

const payload = [
    {
        toolName: "手机",
        normName: "营销量",
        timeRange: "2021-11",
        value: 145
    },
    {
        toolName: "手机",
        normName: "营销额",
        timeRange: "2021-11",
        value: 6
    },
    {
        toolName: "平板",
        normName: "营销量",
        timeRange: "2021-11",
        value: 10
    },
    {
        toolName: "平板",
        normName: "营销额",
        timeRange: "2021-11",
        value: 1354.64
    },
    {
        toolName: "电脑",
        normName: "营销量",
        timeRange: "2021-11",
        value: 1000
    },
    {
        toolName: "手机",
        normName: "营销量",
        timeRange: "2021-12",
        value: 42
    },
    {
        toolName: "手机",
        normName: "营销额",
        timeRange: "2021-12",
        value: 60
    },
    {
        toolName: "平板",
        normName: "营销量",
        timeRange: "2021-12",
        value: 8
    },
    {
        toolName: "平板",
        normName: "营销额",
        timeRange: "2021-12",
        value: 1200
    },
    {
        toolName: "电脑",
        normName: "营销量",
        timeRange: "2021-12",
        value: 872
    }
];

const r = groupIt(payload);
console.dir(r, { depth: null });

输出

{
  '手机': [
    {
      normName: '营销量',
      timeRange: [ '2021-11', '2021-12' ],
      value: [ 145, 42 ]
    },
    {
      normName: '营销额',
      timeRange: [ '2021-11', '2021-12' ],
      value: [ 6, 60 ]
    }
  ],
  '平板': [
    {
      normName: '营销量',
      timeRange: [ '2021-11', '2021-12' ],
      value: [ 10, 8 ]
    },
    {
      normName: '营销额',
      timeRange: [ '2021-11', '2021-12' ],
      value: [ 1354.64, 1200 ]
    }
  ],
  '电脑': [
    {
      normName: '营销量',
      timeRange: [ '2021-11', '2021-12' ],
      value: [ 1000, 872 ]
    }
  ]
}

送你一套简单且好理解的算法:

const merge = (payload: any) => {
    const res = [];
    payload.forEach(p => {
        let t = res.find(x => x[p.toolName]);
        if (!t) {
            t = {[p.toolName]: []};
            res.push(t);
        }
        let tt = t[p.toolName].find(x => x.normName === p.normName);
        if (!tt) {
            tt = {normName: p.normName, timeRange: [], value: []};
            t[p.toolName].push(tt);
        }
        tt.timeRange.push(p.timeRange);
        tt.value.push(p.value);
    })
    return res;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题