遍历对象并根据现有值更新值
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
.
为同一路径添加 visits
和 clicks
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);
我有一个 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
.
visits
和 clicks
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);