Reputation: 1
I have an array of objects in Javascript like:
var arrobj = [
{'id': 1, 'editors': 'Andrew||Maria', 'authors': 'Dorian||Gabi', 'agents': 'Bob||Peter'},
{'id': 2, 'editors': 'Dorian||Guybrush', 'author': 'Peter||Frodo', 'agents': 'Dorian||Otto'},
{'id': 3, 'editors': 'Klaus||Otmar', 'authors': 'Jordan||Morgan', 'agents': 'Jordan||Peter'},
];
I need to make a list of all people (editors, authors & agents) occurring in each object with his/her role. The output should contain a new key/value-pair ('involved') looking like this:
'involved': 'Andrew (editor)|| Maria (editor)|| Dorian (author) || Gabi (author) || Bob (agent) || Peter (agent)'
The array of objects should be something like:
var arrobj = [
{'id': 1, 'editors': 'Andrew||Maria', 'authors': 'Dorian||Gabi', 'agents': 'Bob||Peter', 'involved': 'Andrew (editor)|| Maria (editor)|| Dorian (author) || Gabi (author) || Bob (agent) || Peter (agent)'},
{'id': 2, 'editors': 'Dorian||Guybrush', 'authors': 'Peter||Frodo', 'agents': 'Dorian||Otto','involved': 'Dorian (editor, agent) || Gybrush (editor) || Peter (author) || Frodo (author) || Otto (author)'},
{'id': 3, 'editors': 'Klaus||Otmar', 'authors': 'Jordan||Morgan', 'agents': 'Jordan||Peter','involved': 'Klaus (editor) || Otmar (editor) || Jordan (author, agent) || Morgan (author) || Peter (agent)'},
];
If a person is associated to multiple roles (e.g. id 2 --> Dorian occurs in editors & agents), their occurrence in 'involved' should be only once but with both roles in brackets (e.g. Dorian (editor, agent) )
I am very new to programming and cannot think of a way to do it properly. At a first step I guess I have to split all values by "||" into arrays and then compare each name with every other name in the array.
I would really appreciate some help on my problem.
Upvotes: 0
Views: 86
Reputation: 10655
const arrobj = [
{'id': 1, 'editors': 'Andrew||Maria', 'authors': 'Dorian||Gabi', 'agents': 'Bob||Peter'},
{'id': 2, 'editors': 'Dorian||Guybrush', 'authors': 'Peter||Frodo', 'agents': 'Dorian||Otto'},
{'id': 3, 'editors': 'Klaus||Otmar', 'authors': 'Jordan||Morgan', 'agents': 'Jordan||Peter'},
];
for (let obj of arrobj) {
obj.involved = "";
for (let key of Object.keys(obj)) {
let strKey = [...key];
strKey.pop();
let role = strKey.join("");
if (key === "involved") break;
if (key !== "id") {
obj.involved += obj[key]
.split("||")
.map((name) => name + "(" + role + ")||")
.join("");
}
obj.involved = obj.involved.substr(0, obj.involved.length - 2).trim();
}
}
console.log(arrobj);
here is the running repl: https://repl.it/join/juljqzxt-theketan2
Upvotes: 0
Reputation: 35222
map
the array and destructure each object to get a roles
object without id
.
Create a map
object which will map each person to an array of their roles
Loop through each key in the roles
object and split
at ||
to get an array of names
Loop through the names and update the map
object. If the name
hasn't been already added, add it using ||=
assignment
Remove the last character of the role using slice
to convert it from plural to singular ("agents" to "agent")
The map
object now has each person as key and an array of roles as value.
{
Dorian: ["editor", "agent"],
Guybrush: ["editor"],
Peter: ["author"],
Frodo: ["author"],
Otto: ["agent"]
}
Loop through the entries of the object and create the involved
string
return a new object with an additional involved
key
const arrobj = [
{'id': 1, 'editors': 'Andrew||Maria', 'authors': 'Dorian||Gabi', 'agents': 'Bob||Peter'},
{'id': 2, 'editors': 'Dorian||Guybrush', 'authors': 'Peter||Frodo', 'agents': 'Dorian||Otto'},
{'id': 3, 'editors': 'Klaus||Otmar', 'authors': 'Jordan||Morgan', 'agents': 'Jordan||Peter'},
];
const output = arrobj.map(({ id, ...roles }) => {
const map = {}
for (const r in roles) {
const names = roles[r].split("||")
for (const name of names) {
map[name] ||= []
map[name].push(r.slice(0,-1))
}
}
const involved = Object.entries(map)
.map(([name, values]) => `${name} (${values.join(", ")})`)
.join(" || ")
return { id, ...roles, involved }
})
console.log(output)
Upvotes: 1
Reputation: 3549
This is an example of solution (ES5), there are some optimization possible. The basic idea is to push all the editors, the for the authors and agents check if it already exist in the previously composed array.
var arrobj = [
{'id': 1, 'editors': 'Andrew||Maria', 'authors': 'Dorian||Gabi', 'agents': 'Bob||Peter'},
{'id': 2, 'editors': 'Dorian||Guybrush', 'authors': 'Peter||Frodo', 'agents': 'Dorian||Otto'},
{'id': 3, 'editors': 'Klaus||Otmar', 'authors': 'Jordan||Morgan', 'agents': 'Jordan||Peter'},
];
function getInvolved(arr) {
return arr.map(function(el) {
var editors = el.editors.split('||');
var authors = el.authors.split('||');
var agents = el.agents.split('||');
var involved = editors.map(function(editor) {
return editor += ' (editor)';
});
authors.forEach(function(author) {
if(editors.indexOf(author) === -1) {
involved.push(author + ' (author)');
} else {
involved = involved.map(function(inv) {
if(inv.indexOf(author) > -1) {
inv += '(author)';
}
return inv;
});
}
});
agents.forEach(function(agent) {
if(editors.indexOf(agent) === -1 && authors.indexOf(agent) === -1) {
involved.push(agent + ' (agent)');
} else {
involved = involved.map(function(inv) {
if(inv.indexOf(agent) > -1) {
inv += '(agent)';
}
return inv;
});
}
});
el.involved = involved.join('||');
return el;
});
}
console.log(getInvolved(arrobj));
Upvotes: 0
Reputation: 386604
You need to collect all names with their job types and return a grouped result.
const
getInvolved = o => {
const
jobs = ['editor', 'author', 'agent'],
names = jobs.reduce((r, k) => {
(o[k + 's'] || '').split('||').forEach(v => (r[v] ??= []).push(k));
return r;
}, {});
return Object.entries(names).map(([k, v]) => `${k} (${v.join(', ')})`).join(' || ')
},
array = [{ id: 1, editors: 'Andrew||Maria', authors: 'Dorian||Gabi', agents: 'Bob||Peter' }, { id: 2, editors: 'Dorian||Guybrush', author: 'Peter||Frodo', agents: 'Dorian||Otto' }, { id: 3, editors: 'Klaus||Otmar', authors: 'Jordan||Morgan', agents: 'Jordan||Peter' }],
result = array.map(o => ({ ...o, involved: getInvolved(o) }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1