如何使用 lodash 按嵌套属性分组?
Posted
技术标签:
【中文标题】如何使用 lodash 按嵌套属性分组?【英文标题】:how to group by nested properties using lodash? 【发布时间】:2019-07-29 06:43:26 【问题描述】:我有一个对象数组
"work": [
"_id": "5c80c5c00c253823fc443337",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-01-02T18:30:00.000Z",
"employee":
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
,
"allocation": 30
,
"_id": "5c80c5ef0c253823fc443339",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-09-30T18:30:00.000Z",
"employee":
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
,
"allocation": 100
,
"_id": "5c80c60b0c253823fc44333a",
"start": "2018-12-31T18:30:00.000Z",
"end": "2020-10-07T18:30:00.000Z",
"employee":
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
,
"allocation": 25
,
"_id": "5c80c65e0c253823fc44333b",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-10-04T18:30:00.000Z",
"employee":
"_id": "5c80c1940c253823fc44332b",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
,
"allocation": 50
,
"_id": "5c80c7240c253823fc44333f",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-10-09T18:30:00.000Z",
"employee":
"_id": "5c80c26e0c253823fc44332e",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
,
"allocation": 25
]
我需要将它们转换成
[
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890",
"work": [
"_id": "5c80c5c00c253823fc443337",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-01-02T18:30:00.000Z",
"allocation": 30
,
"_id": "5c80c5ef0c253823fc443339",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-09-30T18:30:00.000Z",
"allocation": 100
,
"_id": "5c80c60b0c253823fc44333a",
"start": "2018-12-31T18:30:00.000Z",
"end": "2020-10-07T18:30:00.000Z",
"allocation": 25
]
,
"_id": "5c80c1940c253823fc44332b",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890",
"work": [
"_id": "5c80c65e0c253823fc44333b",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-10-04T18:30:00.000Z",
"allocation": 50
]
,
"_id": "5c80c26e0c253823fc44332e",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890",
"work": [
"_id": "5c80c7240c253823fc44333f",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-10-09T18:30:00.000Z",
"allocation": 25
]
]
我已经通过部分使用 lodash 和 vanilla js 完成了它,它完全可以正常工作。但可读性完全不好。我想单独使用 lodash 来实现这一点。有什么帮助吗?
let ids: any = groupBy(this.project.work, function (res)
return res.employee._id;
);
for (let id in ids)
let tmp = [];
let employee_added = false;
ids[id].map((work) =>
if (!employee_added)
tmp = work.employee;
tmp['work'] = [];
employee_added = true;
delete work.employee;
tmp['work'].push(work);
)
this.employees.push(tmp);
console.log(this.employees);
【问题讨论】:
【参考方案1】:希望这就是您正在寻找的。p>
-
首先按
employee_.id
分组
然后映射每个组,获取第一个员工(因为每个组
必须有一个条目)
然后将每个组的所有其他成员(并取出外部部分)映射到work
(除员工对象之外的所有内容)
下面是一个例子:
let works = ["_id":"5c80c5c00c253823fc443337","start":"2019-01-01T18:30:00.000Z","end":"2019-01-02T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":30,"_id":"5c80c5ef0c253823fc443339","start":"2018-12-31T18:30:00.000Z","end":"2019-09-30T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":100,"_id":"5c80c60b0c253823fc44333a","start":"2018-12-31T18:30:00.000Z","end":"2020-10-07T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":25,"_id":"5c80c65e0c253823fc44333b","start":"2019-01-01T18:30:00.000Z","end":"2019-10-04T18:30:00.000Z","employee":"_id":"5c80c1940c253823fc44332b","status":"active","location":"Chennai","contact_number":"1234567890","allocation":50,"_id":"5c80c7240c253823fc44333f","start":"2018-12-31T18:30:00.000Z","end":"2019-10-09T18:30:00.000Z","employee":"_id":"5c80c26e0c253823fc44332e","status":"active","location":"Chennai","contact_number":"1234567890","allocation":25]
let res = _(works)
.groupBy('employee._id')
.map(g => (...g[0].employee, work: _.map(g, (employee, ...rest) => (...rest))))
.value();
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
【讨论】:
【参考方案2】:您可以创建一个使用 lodash 的 _.flow()
按员工 ID 分组的函数,然后使用工作数组创建一个员工对象:
const flow, partialRight: pr, groupBy, map, head, get, omit = _
const fn = flow(
pr(groupBy, 'employee._id'),
pr(map, group => ( // create the employee objects
...get(head(group), 'employee'), // get the employee data and spread it
work: group.map(o => omit(o, 'employee')) // create the work array by removing the employee from each work object
))
)
const data = "work":["_id":"5c80c5c00c253823fc443337","start":"2019-01-01T18:30:00.000Z","end":"2019-01-02T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":30,"_id":"5c80c5ef0c253823fc443339","start":"2018-12-31T18:30:00.000Z","end":"2019-09-30T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":100,"_id":"5c80c60b0c253823fc44333a","start":"2018-12-31T18:30:00.000Z","end":"2020-10-07T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":25,"_id":"5c80c65e0c253823fc44333b","start":"2019-01-01T18:30:00.000Z","end":"2019-10-04T18:30:00.000Z","employee":"_id":"5c80c1940c253823fc44332b","status":"active","location":"Chennai","contact_number":"1234567890","allocation":50,"_id":"5c80c7240c253823fc44333f","start":"2018-12-31T18:30:00.000Z","end":"2019-10-09T18:30:00.000Z","employee":"_id":"5c80c26e0c253823fc44332e","status":"active","location":"Chennai","contact_number":"1234567890","allocation":25]
const result = fn(data.work)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
【讨论】:
完美+1,谢谢 @OriDrori 尽量避免使用omit
,而是将其余属性设为employee, ...rest
并使用rest
【参考方案3】:
您可以使用带有 Object.values()
、Array.reduce()
和解构分配的纯 javascript 简洁地做到这一点:
const data = "work":["_id":"5c80c5c00c253823fc443337","start":"2019-01-01T18:30:00.000Z","end":"2019-01-02T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":30,"_id":"5c80c5ef0c253823fc443339","start":"2018-12-31T18:30:00.000Z","end":"2019-09-30T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":100,"_id":"5c80c60b0c253823fc44333a","start":"2018-12-31T18:30:00.000Z","end":"2020-10-07T18:30:00.000Z","employee":"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890","allocation":25,"_id":"5c80c65e0c253823fc44333b","start":"2019-01-01T18:30:00.000Z","end":"2019-10-04T18:30:00.000Z","employee":"_id":"5c80c1940c253823fc44332b","status":"active","location":"Chennai","contact_number":"1234567890","allocation":50,"_id":"5c80c7240c253823fc44333f","start":"2018-12-31T18:30:00.000Z","end":"2019-10-09T18:30:00.000Z","employee":"_id":"5c80c26e0c253823fc44332e","status":"active","location":"Chennai","contact_number":"1234567890","allocation":25];
const result = Object.values(data.work.reduce((acc, work) =>
const employee: _id, ...rest , ...job = work;
const jobs = (acc[_id] || ).work || [];
acc[_id] = _id, ...rest, work: [...jobs, job] ;
return acc;
, ));
console.log(result);
【讨论】:
谢谢 +1 整洁,但我正在寻找 lodash 的答案,无论如何我会接受你的答案,如果我找不到任何与 lodash 相关的内容。 @Thamaraiselvam 不明白您为什么接受答案的 loadash 版本(我的和 Ori Drori 的答案)然后不接受。这个使用普通 JS 的答案看起来不错,然后你要求 lodash versoin(在这个 ans 的最后一条评论中),之后我想出了一些 lodash 解决方案(认为这可能对你有帮助)。不知道你到底在找什么。 @KoushikChatterjee 您在发布最佳答案方面做得非常出色。由于我使用的是 typescript ,因此您的答案存在一些语法问题,我很着急,所以我使用了 jo_va 答案。 @Thamaraiselvam 嗯,实际上这与我的答案或任何人的答案无关,如果您有任何问题,请评论您应该在那里评论的任何答案,以便为所有 SO 用户提供更大的图景可能会遇到这种问题。以上是关于如何使用 lodash 按嵌套属性分组?的主要内容,如果未能解决你的问题,请参考以下文章