js数据处理

原数据

const data = [
    { value: 1, name: 'Search Engine' },
    { value: 1, name: 'Direct' },
    { value: 5, name: 'Email' },
    { value: 1, name: 'Union Ads' },
    { value: 6, name: 'Video Ads' },
    { value: 1, name: 'Search Engine' },
    { value: 7, name: 'Direct' },
    { value: 1, name: 'Email' },
    { value: 1, name: 'Union Ads' },
    { value: 8, name: 'Video Ads' },
];

期望结果:

0: {name: 'Search Engine', Search Engine: 2}
1: {name: 'Direct', Direct: 14}
2: {name: 'Email', Email: 2}
3: {name: 'Union Ads', Union Ads: 2}
4: {name: 'Video Ads', Video Ads: 16}

我的处理方式

let f = data.reduce((result, el) => {
    let group = result.find(item => item.name == el.name);
    if (!group) {
        group = {
            name: el.name,
        }
        result.push(group)
    }
    let total = el.value += el.value;
    group[el.name] = total;
    return result
}, []);
console.log(f)

想请问各位大佬,上面的数据处理还有什么更好的解法吗

阅读 1.4k
4 个回答

如果是要对相同 namevalue 求和,可以这样写

data.reduce((o, e) => (o[e.name] = (o[e.name] ?? 0) + e.value, o), {})
// {Search Engine: 2, Direct: 8, Email: 6, Union Ads: 2, Video Ads: 14}

没太看明白,你那个结果,看着是 name 相同的 value 相加,可你这 Direct ,1 + 7 的结果,怎么成了 14 去了的。。

const data = [
  { value: 1, name: 'Search Engine' },
  { value: 1, name: 'Direct' },
  { value: 5, name: 'Email' },
  { value: 1, name: 'Union Ads' },
  { value: 6, name: 'Video Ads' },
  { value: 1, name: 'Search Engine' },
  { value: 7, name: 'Direct' },
  { value: 1, name: 'Email' },
  { value: 1, name: 'Union Ads' },
  { value: 8, name: 'Video Ads' },

]

const vd = Object.entries(data.reduce((r, c) => ((r[c.name] = (r[c.name] || 0) + c.value, r)), {}))
  .map(([name, value]) => ({ name, [name]: value }))

console.log(vd)

根据你的代码和结果,估摸着你是需要把 name 相同项项 value 加起来。不过从结果来看,代码应该有错,比如 Direct 的值合计是 8 而不是 14。没仔细看代码,不过至少 total = el.value += el.value 这里应该是的问题的。

思路是,先按 name 分组,然后按各组统计 value,最后按需要的形式组合成对象。如果用 Lodash 来写,应该是这样:

import _ from "lodash";

//... data 定义

const result = _(data)
    .groupBy("name")
    .mapValues(list => _.sumBy(list, it => it.value))
    .entries()
    .map(([name, value]) => ({ name, [name]: value }))
    .value();

如果要用 reduce 来写

const result = data.reduce((acc, it) => {
    // 在结果中按 it.name 查找,看是否已经保存了有
    let accIt = acc.find(({ name }) => name === it.name);

    // 如果没保存到有,产生一个新的对象,value 值初始为 0,对象压入数组。
    // 这个对象由 accIt 引用,所以 accIt 现在与找到的引用行为一致
    if (!accIt) {
        accIt = { name: it.name, [it.name]: 0 };
        acc.push(accIt);
    }

    // 将 it.value 计入当前元素 (accIt) 的 value 值,
    // 注意取值是用[it.name] 来找的(根据题目要求)
    accIt[it.name] += it.value;
    return acc;
}, []);

两段代码的结果都是:

[
  { name: 'Search Engine', 'Search Engine': 2 },
  { name: 'Direct', Direct: 8 },
  { name: 'Email', Email: 6 },
  { name: 'Union Ads', 'Union Ads': 2 },
  { name: 'Video Ads', 'Video Ads': 14 }
]

线性复杂度

const reduce = (data) => {
    const res = {};
    for (const {value, name} of data) {
        if( res[name] === undefined) res[name] = 0;
        res[name] += value;
    }
    return Object.entries(res).map(([k,v]) => ({name:k, [k]: v}))
}

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