Reputation: 637
I'm trying to arrange my current object, which looks like below
var myValues = [
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: "FIREFOX",
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: "BUZZZZZZ",
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "PANTER",
firstname: "Panty",
id: "[email protected]",
arrangeid: "PANTER",
region: "PAN",
secondname: "mc panty",
status: "Approved"
},
{
client: "BAT",
firstname: "Bruce",
id: "[email protected]",
arrangeid: "BLACKBAT",
region: "BLK",
secondname: "Wyne",
status: "Approved"
}
]
So I've got this object, the first two ID's are the same but they got different arrangeid. I wanna be able to join the them to gather them together. Where the object looks something like this:
var myValues = [
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: ["BUZZZZZZ", "FIREFOX"],
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "PANTER",
firstname: "Panty",
id: "[email protected]",
arrangeid: ["PANTER"],
region: "PAN",
secondname: "mc panty",
status: "Approved"
},
{
client: "BAT",
firstname: "Bruce",
id: "[email protected]",
arrangeid: ["BLACKBAT"],
region: "BLK",
secondname: "Wyne",
status: "Approved"
}
]
I have a jsfidle here, where i kinda get a result. Can it be done better, cleaner. Have I approached it correctly?
Upvotes: 0
Views: 50
Reputation: 50797
Here is a slightly more generic approach, which lets you group by any combination of fields and then merge some given ones into an array:
const pick = (fields, obj) => fields.reduce((o, fld) => ({...o, [fld]: obj[fld]}), {})
const groupAndMerge = (groupFields, mergeFields, xs) =>
Object.values(xs.reduce(
(a, x, _, __, key = JSON.stringify(pick(groupFields, x))) =>
(a[key] = (a[key] || []).concat(x)) && a,
{}
)).map(xs => ({
...xs[0],
...mergeFields.reduce((a, f) => ({...a, [f]: xs.map(x => x[f])}), {})
}))
const myValues = [{arrangeid: "FIREFOX", client: "FIRE", firstname: "Test", fid: "[email protected]", region: "FOP", secondname: "Testy", status: "Approved"}, {arrangeid: "BUZZZZZZ", client: "FIRE", firstname: "Test", fid: "[email protected]", region: "FOP", secondname: "Testy", status: "Approved"}, {arrangeid: "PANTER", client: "PANTER", firstname: "Panty", fid: "[email protected]", region: "PAN", secondname: "mc panty", status: "Approved"}, {arrangeid: "BLACKBAT", client: "BAT", firstname: "Bruce", fid: "[email protected]", region: "BLK", secondname: "Wyne", status: "Approved"}]
const result = groupAndMerge(['client', 'id'], ['arrangeid'], myValues)
console.log(result)
The helper function pick
simply chooses certain properties of the target object, so that pick(['a', 'c'], {a: 1, b: 2, c: 3}) //=> {a: 1, c: 3}
.
groupAndMerge
uses the first parameter (here ['client', 'id']
) to identify the fields which have to be the same, and the second one (here ['arrangeid']
) to show which ones have to be grouped.
You mention that the first two have the same id
. My code checks both client
and id
; this is as much as anything a proof-of-concept, but it could be useful.
There is one caveat to using this: it only merges well on string or numeric values. Some others might work, but I wouldn't count on it. (That is also true for at least one other answer here, but I don't know if it's important to you.)
The advantage I see to this is that it's only slightly more complex than a bespoke implementation, and it's useful in a number of other circumstances.
Upvotes: 0
Reputation: 707546
For larger data sets, you can use the lookup capabilities of a Map
object to collect all the items for each id and then you can convert that result into whatever format you want. You can run this snippet to see the result.
function collectByField(data, key, prop) {
const collection = new Map();
for (const obj of data) {
let item = collection.get(obj[key]);
if (item) {
// add this item's property to the array
item[prop].push(obj[prop]);
} else {
// put a copy of our object into the Map
// convert prop to an array with one initial item in it
let copy = Object.assign({}, obj);
copy[prop] = [obj[prop]];
collection.set(obj[key], copy);
}
}
// now use the Set to create final array output
return Array.from(collection.values());
}
let myValues = [
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: "FIREFOX",
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: "BUZZZZZZ",
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "PANTER",
firstname: "Panty",
id: "[email protected]",
arrangeid: "PANTER",
region: "PAN",
secondname: "mc panty",
status: "Approved"
},
{
client: "BAT",
firstname: "Bruce",
id: "[email protected]",
arrangeid: "BLACKBAT",
region: "BLK",
secondname: "Wyne",
status: "Approved"
}
];
console.log(collectByField(myValues, "id", "arrangeid"));
Upvotes: 0
Reputation: 350365
You could create a Map to key the objects by their id, and then populate the arrangeid
arrays:
const myValues = [{client: "FIRE",firstname: "Test",id: "[email protected]",arrangeid: "FIREFOX",region: "FOP",secondname: "Testy",status: "Approved"},{client: "FIRE",firstname: "Test",id: "[email protected]",arrangeid: "BUZZZZZZ",region: "FOP",secondname: "Testy",status: "Approved"}, {client: "PANTER",firstname: "Panty",id: "[email protected]",arrangeid: "PANTER",region: "PAN",secondname: "mc panty",status: "Approved"},{client: "BAT",firstname: "Bruce",id: "[email protected]",arrangeid: "BLACKBAT",region: "BLK",secondname: "Wyne",status: "Approved"}];
const map = new Map(myValues.map(o => [o.id, {...o, arrangeid: []}]));
myValues.forEach(o => map.get(o.id).arrangeid.push(o.arrangeid));
const result = [...map.values()];
console.log(result);
Upvotes: 0
Reputation: 35242
You can use reduce
, Object.values()
and spread syntax like this:
var myValues = [{client:"FIRE",firstname:"Test",id:"[email protected]",arrangeid:"FIREFOX",region:"FOP",secondname:"Testy",status:"Approved"},{client:"FIRE",firstname:"Test",id:"[email protected]",arrangeid:"BUZZZZZZ",region:"FOP",secondname:"Testy",status:"Approved"},{client:"PANTER",firstname:"Panty",id:"[email protected]",arrangeid:"PANTER",region:"PAN",secondname:"mc panty",status:"Approved"},{client:"BAT",firstname:"Bruce",id:"[email protected]",arrangeid:"BLACKBAT",region:"BLK",secondname:"Wyne",status:"Approved"}];
const merged = myValues.reduce((acc, a) => {
acc[a.client] = acc[a.client] || { ...a, arrangeid: [] };
acc[a.client].arrangeid.push(a.arrangeid);
return acc;
},{})
const output = Object.values(merged);
console.log(output)
The accumulator is an object with each unique client
as its key so that it's easier to group them.
{
"FIRE": {
"client": "FIRE",
"firstname": "Test",
"id": "[email protected]",
"arrangeid": [ "FIREFOX", "BUZZZZZZ" ],
"region": "FOP",
"secondname": "Testy",
"status": "Approved"
},
"PANTER": {
"client": "PANTER",
"id": "[email protected]",
"arrangeid": [
"PANTER"
],
...
}
...
}
Upvotes: 1
Reputation: 36584
You can use reduce()
var myValues = [
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: "FIREFOX",
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "FIRE",
firstname: "Test",
id: "[email protected]",
arrangeid: "BUZZZZZZ",
region: "FOP",
secondname: "Testy",
status: "Approved"
},
{
client: "PANTER",
firstname: "Panty",
id: "[email protected]",
arrangeid: "PANTER",
region: "PAN",
secondname: "mc panty",
status: "Approved"
},
{
client: "BAT",
firstname: "Bruce",
id: "[email protected]",
arrangeid: "BLACKBAT",
region: "BLK",
secondname: "Wyne",
status: "Approved"
}
]
let res = JSON.parse(JSON.stringify(myValues)).reduce((ac,a) => {
let ind = ac.findIndex(x => x.id === a.id);
a.arrangeid = [a.arrangeid];
ind === -1 ? ac.push(a) : ac[ind].arrangeid.push(...a.arrangeid);
return ac;
},[])
console.log(res);
Upvotes: 0