I want to convert this array:
[{
department: 'HR',
person: 'Tom'
},{
department: 'Finance',
person: 'Peter'
},{
department: 'HR',
person: 'Jane'
}];
Into this one, grouping people by department
and changing the keys
[{
role: 'HR',
people: ['Tom','Jane']
},{
role: 'Finance',
people: ['Peter']
}]
I use this technique that have seem around and works really well, I am not really sure if it's got a name.
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; }
Using the ES6 Map object I can do the same with this
const data = [{department: 'HR', person: 'Tom'},{department: 'Finance',person: 'Peter'},{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; }
Is this approach better in any way, is there another way to use Map
to get the same result?
There's a fundamental difference between object properties and keys in a key-value store.
A property is something you define at the coding time, it has a fixed name and a well-defined meaning. A property is similar to a variable or a function.
A key is something that is only known at the run time, it is dynamic and has no inherent meaning except being associated with some value. A key is like an array index.
In the past, javascript Object
s were misused to emulate key-value stores, using property names as keys. This had several serious drawbacks
hasOwnProperty
etc)The Map
was invented to address these drawbacks specifically:
Map
keys can be anything Map
keys are always in insertion order Therefore, if you need a key-value store, Map
is always a better choice. Using generic Objects for this is a mistake.
As for the "better" way to use Maps for grouping, this is rather subjective. I'd prefer a more generic version
/// 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;
}
which can be used like this for the task at hand:
let result = [];
for (let [role, items] of groupBy(data, x => x.department))
result.push({role, people: items.map(x => x.person)})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.