如何解决ES6 映射对象以对值进行分组
我想转换这个数组:
[{
department: 'HR',person: 'Tom'
},{
department: 'Finance',person: 'Peter'
},{
department: 'HR',person: 'Jane'
}];
进入这个,通过department
对人进行分组并更改密钥
[{
role: 'HR',people: ['Tom','Jane']
},{
role: 'Finance',people: ['Peter']
}]
我使用的这种技术看起来很流行并且效果很好,我不确定它是否有名字。
const data = [{department: 'HR',person: 'Tom'},{department: 'Finance',person: 'Peter'},{department: 'HR',person: 'Jane'}];
function groupPeopleByDepartmentWithObj(data) {
const obj = {};
for (const { department,person} of data) {
if (!obj[department]) {
obj[department] = { role: department,people: []};
}
obj[department].people.push(person);
}
return Object.values(obj);
}
console.log(groupPeopleByDepartmentWithObj(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
使用 ES6 Map 对象,我也可以这样做
const data = [{department: 'HR',person: 'Jane'}];
function groupPeopleByDepartmentWithMap(data) {
const mapper = new Map()
for (const { department,person} of data) {
if (!mapper.has(department)) {
mapper.set(department,{ role: department,people: []})
}
mapper.get(department).people.push(person)
}
return Array.from(mapper.values())
}
console.log(groupPeopleByDepartmentWithMap(data))
.as-console-wrapper { max-height: 100% !important; top: 0; }
这种方法在任何方面都更好吗?还有其他方法可以使用 Map
来获得相同的结果吗?
解决方法
键值存储中的对象属性和键之间存在根本区别。
属性是您在编码时定义的东西,它具有固定的名称和明确定义的含义。属性类似于变量或函数。
键是只在运行时才知道的东西,它是动态的,除了与某些值相关联之外没有任何内在意义。一个键就像一个数组索引。
过去,javascript Object
被滥用来模拟键值存储,使用属性名称作为键。这有几个严重的缺点
- 属性名称和键只能是字符串
- 属性通常不排序
- 关键迭代很笨拙(
hasOwnProperty
等) - 由于属性和键之间没有区别,因此动态键可能会意外覆盖已定义的属性,反之亦然,现有属性可能会被误认为是键
发明 Map
是为了专门解决这些缺点:
-
Map
键可以是任何东西 -
Map
键始终按插入顺序排列 - 关键迭代定义明确
- 键和属性位于不同的命名空间中,不会相互覆盖
因此,如果您需要键值存储,Map
始终是更好的选择。为此使用通用对象是错误的。
至于使用地图进行分组的“更好”方式,这是相当主观的。我更喜欢更通用的版本
/// data: an Iterable
/// keyFn: a function which will be applied to each data item to obtain its group key
/// returns: a Map(key => [items])
// function groupBy<T,K>(data: Iterable<T>,keyFn: (x: T) => K): Map<K,T[]>
//
function groupBy(data,keyFn) {
let m = new Map();
for (let x of data) {
let k = keyFn(x);
if (!m.has(k))
m.set(k,[]);
m.get(k).push(x);
}
return m;
}
可以像这样用于手头的任务:
let result = [];
for (let [role,items] of groupBy(data,x => x.department))
result.push({role,people: items.map(x => x.person)})
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。