Reputation: 95
I have an array of objects similar to
const array = [
{
documentId: "document1",
writers: [
{
name: "writer1",
date: "2017-12-11"
},
{
name: "writer2",
date: "2017-12-11"
}
]
},
{
documentId: "document2",
writers: [
{
name: "writer1",
date: "2017-12-11"
},
{
name: "writer3",
date: "2017-12-11"
}
]
},
{
documentId: "document3",
writers: [
{
name: "writer3",
date: "2017-12-11"
},
{
name: "writer4",
date: "2017-12-11"
}
]
},
I'm trying to extract all the unique writer's names and match them to all the documents they have written so that the final array looks something like this:
const finalArray = [
{name: "writter1", documents: ["document1", "document2"]},
{name: "writter2", documents: ["document1"]},
{name: "writter3", documents: ["document2", "document3"]},
{name: "writter4", documents: ["document3"]}
]
Upvotes: 1
Views: 65
Reputation: 386560
You could take a Map
which takes all names and the associated documents. If no map is avaliable for a name, then create a new entry.
A then end, get all objects of the map.
var array = [{ documentId: "document1", writers: [{ name: "writer1", date: "2017-12-11" }, { name: "writer2", date: "2017-12-11" }] }, { documentId: "document2", writers: [{ name: "writer1", date: "2017-12-11" }, { name: "writer3", date: "2017-12-11" }] }, { documentId: "document3", writers: [{ name: "writer3", date: "2017-12-11" }, { name: "writer4", date: "2017-12-11" }] }],
map = new Map,
result;
array.forEach(function (o) {
o.writers.forEach(function ({ name }) {
map.has(name) || map.set(name, { name, documents: [] });
map.get(name).documents.push(o.documentId);
});
});
result = Array.from(map.values());
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 2704
You can use Map
to keep writers as keys then call reduce
on your array to map documents to writers, then call values()
on the Map
object:
const ret = Array.from(array.reduce((acc, val) => {
val.writers.forEach(({ name }) => {
let w = acc.get(name) || { name: name, documents: [] };
w.documents = w.documents.concat(val.documentId);
acc.set(name, w);
});
return acc;
}, new Map()).values());
console.log(ret);
Upvotes: 2
Reputation: 2220
Maybe there will be a more elegant map-reduce solution. Anyway, this will works even if it's ugly:
const array = //your data
var output = []
for (let i = 0; i < array.length; i++)
for (let k = 0; k < array[i].writers.length; k++) {
let t = output.find(function(a){return array[i].writers[k].name === a.name})
if (t)
t.documents.push(array[i].documentId)
else
output.push({name: array[i].writers[k].name, documents: [array[i].documentId]})
}
console.log(output)
https://jsfiddle.net/50oph5g4/1/
Upvotes: 1