【问题标题】:Iterating through an object and updating values based on existing values遍历对象并根据现有值更新值
【发布时间】:2021-10-16 06:56:06
【问题描述】:

我有一个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

  }
});

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

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

【问题讨论】:

    标签: javascript json lodash


    【解决方案1】:

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

    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);

    【讨论】:

      【解决方案2】:

      您可以基于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);

      【讨论】:

        【解决方案3】:

        初始解构映射数组,使用 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];
            }, [])
        
        

        【讨论】:

        • Syntax error: unexpected token '...' at ...rest.
        【解决方案4】:

        我认为您想根据 path 对数据进行分组,但您的示例结果没有这样做,它有两个条目用于“/home/page1”,而没有“/home/page3” ",我认为这只是帖子中的一个错误。

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

        如果数组变得非常大,每次查看聚合数组的 path 可能会变得很昂贵,因此请考虑将 path 的索引对象创建到聚合数据数组,这样它就是只需两次查找(一次获取索引,然后另一次获取对象),而不是每次都搜索数组。例如。 (恐怕没有 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);

        【讨论】:

          猜你喜欢
          • 2021-07-10
          • 1970-01-01
          • 2016-07-27
          • 1970-01-01
          • 1970-01-01
          • 2020-01-19
          • 2022-01-07
          • 1970-01-01
          • 2016-12-19
          相关资源
          最近更新 更多