遍历对象并根据现有值更新值

Iterating through an object and updating values based on existing values

我有一个 data json 结构如下的对象:

data: [{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=todd"
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=matt"
  },
  "visits": 5,
  "clicks": 17
},{
  "aggregate": {
    "path": "/home/page2",
    "query": ""
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page3",
    "query": "term=dig"
  },
  "visits": 2,
  "clicks": 20
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "term=dug"
  },
  "visits": 2,
  "clicks": 11
}]

我希望最终得到这样的 aggregatedObject 对象:

[{
  "path": "/home/page1",
  "visits": 9,
  "clicks": 24
},{
  "path": "/home/page2",
  "visits": 4,
  "clicks": 7
},{
  "path": "/home/page1",
  "visits": 4,
  "clicks": 31
}]

这是我目前拥有的:

let aggregatedObject = [];

_.each(data, function (item) {

  if (!_.find(aggregatedObject, { path: item.aggregate.path })) {
    aggregatedObject.push({
      path: item.aggregate.path,
      visits: item.visits,
      clicks: item.clicks
    });
    //console.log('not found');

  } else {
    // so lost here

  }
});

我想做的是,如果我的新对象没有与我当前正在迭代的项目相匹配的项目,我会将其推送到新对象。到目前为止,我可以成功地做到这一点。

但是,如果我确实找到了与我的新对象中的路径匹配的项目(忽略查询),我不知道如何使用现有项目的访问和点击的总和更新该项目,以及我正在迭代。

我想你想根据 path 对数据进行分组,但你的示例结果并没有这样做,它有两个条目“/home/page1”和 none 对于“/home/page3”,我假设这只是 post.

中的一个错误

您需要测试路径是否已经存在,如果不存在,为其添加一个新的聚合对象,然后添加点击和访问。

如果数组变得非常大,每次查找 path 的聚合数组可能会变得很昂贵,因此考虑创建 path[=27 的索引对象=] 到聚合数据数组,所以它只是两次查找(一次获取索引然后另一个获取对象)而不是每次都搜索数组。例如。 (恐怕没有 lodash):

let data = [{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=todd"
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=matt"
  },
  "visits": 5,
  "clicks": 17
},{
  "aggregate": {
    "path": "/home/page2",
    "query": ""
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page3",
    "query": "term=dig"
  },
  "visits": 2,
  "clicks": 20
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "term=dug"
  },
  "visits": 2,
  "clicks": 11
}];

// Map of path to index in aggArr {path: index}
let pathMap = {};

// Get aggregated array data
let aggData = data.reduce((agg, obj) => {
  let path = obj.aggregate.path;
  
  // If not in index, add it and a new aggregation object
  if (!pathMap.hasOwnProperty(path)) {
    pathMap[path] = agg.length;
    agg.push({path: path, visits:0, clicks:0});
  }

  // target is for convenience, add visits and clicks
  let target = agg[pathMap[path]];
  target.visits += obj.visits; 
  target.clicks += obj.clicks;
  return agg;
}, []);

// Show result
console.log(aggData);

使用 ES6 传播语法,使用初始解构映射数组。然后减少对先前遍历的路径的计算,总结适当路径上的访问和点击。


 const res = data
     .map(({ aggregate, ...rest }) => ({ path: aggregate.path, ...rest }))
     .reduce((acc, c, i, arr) => {
         let curr = Object.assign({}, c);
         const traversed = acc.some(item => item.hasOwnProperty('path') && item.path === curr.path);
         if (traversed) return acc;

         arr.forEach((v, idx) => {
            if (idx !== i && c.path === v.path) {
               curr = { 
                  ...curr, 
                  visits: v.visits + curr.visits, 
                 clicks: v.clicks + curr.clicks 
                } 
           }
        })

       return [...acc, curr];
    }, [])

您可以根据 path 进行分组,并使用 array#reduce.

为同一路径添加 visitsclicks

const data = [{ "aggregate": { "path": "/home/page1", "query": "name=todd" }, "visits": 4, "clicks": 7 },{ "aggregate": { "path": "/home/page1", "query": "name=matt" }, "visits": 5, "clicks": 17 },{ "aggregate": { "path": "/home/page2", "query": "" }, "visits": 4, "clicks": 7 },{ "aggregate": { "path": "/home/page3", "query": "term=dig" }, "visits": 2, "clicks": 20 },{ "aggregate": { "path": "/home/page1", "query": "term=dug" }, "visits": 2, "clicks": 11 }],
    result = Object.values(data.reduce((r, o) => {
      const path = o.aggregate.path;
      r[path] ??= { path, visits: 0, clicks: 0};
      r[path].visits += o.visits;
      r[path].clicks += o.clicks;
      return r;
    },{}));
console.log(result);

我会创建一个对象并将路径名用作聚合器。然后改回数组。

let data = [ {"aggregate": { "path": "/home/page1", "query": "name=todd" }, "visits": 4, "clicks": 7 },
{"aggregate": { "path": "/home/page1", "query": "name=matt"}, "visits": 5, "clicks": 17},
{"aggregate": { "path": "/home/page2", "query": "" },"visits": 4,"clicks": 7},
{"aggregate": { "path": "/home/page3", "query": "term=dig" },"visits": 2, "clicks": 20},
{"aggregate": { "path": "/home/page1", "query": "term=dug" }, "visits": 2, "clicks": 11}];

//let the object path act as the aggregator
let new_data = data.reduce((acc,obj) => {
  let path = obj.aggregate.path;
  acc[path] = { 
      path: path,
      clicks: obj.clicks + (acc[path]?.clicks || 0),
      visits: obj.visits + (acc[path]?.visits || 0)
      };
  return acc;
},{});

//turn the object into an array
new_data = Object.entries(new_data).map(([key,value]) => value);

console.log(new_data);