Is there a better or simplified approach to create an array which contains one object per objectid with an array of contacts that matches globalLkupRemoveContactReviewer by userid and then send each array which contains one object to the database in the form of
[
{
objectid: '222',
contacts: [
{ isdelete: '1', contactid: '1', associationid: '1968398' },
{ isdelete: '1', contactid: '2', associationid: '1968399' },
],
},
];
const globalLkupRemoveContactReviewer = [
{ objectid: 555, userid: '1', associationid: '1948874' },
{ objectid: 555, userid: '2', associationid: '1950833' },
];
//My Code:
var myStr = '111*1*1968397,222*1*1968398,222*2*1968399,333*2*1968401,333*4*1968402,333*1*19684034';
Object.values(
myStr
.split(',')
.map((item) => item.split('*'))
.map(([objectid, userid, associationid]) => ({
objectid,
userid,
associationid,
}))
.filter(
(item1) =>
!!globalLkupRemoveContactReviewer.find(
(item2) => item2.userid === item1.userid
)
)
.reduce((acc, { objectid, userid, associationid }) => {
(acc[objectid] ??= { objectid, contacts: [] }).contacts.push({
isdelete: '1',
contactid: userid,
associationid,
});
return acc;
}, {})
).forEach((item) => {
console.log([item]);
});
// Need result in this format to send to the database
// [ { "objectid": "111", "contacts": [ { "isdelete": "1", "contactid": "1", "associationid": "1968397" } ] } ]
// [ { "objectid": "222", "contacts": [ { "isdelete": "1", "contactid": "1", "associationid": "1968398" }, { "isdelete": "1", "contactid": "2", "associationid": "1968399" } ] } ]
// [ { "objectid": "333", "contacts": [ { "isdelete": "1", "contactid": "2", "associationid": "1968401" }, { "isdelete": "1", "contactid": "1", "associationid": "19684034" } ] } ]
2 Answers 2
If I understand everything correctly, then this can be done easier. The code can be formatted in different ways. But the main thing is that there is less action. So:
- we split the data into parts
- then through reduce we form a common array of objects
- parse data for object (including
objectid
) - check
globalLkupRemoveContactReviewer
if we should add something - to save space, we form a
child
object once - if we have an object with this
objectid
- update it otherwise create it
const globalLkupRemoveContactReviewer = [
{ objectid: 555, userid: '1', associationid: '1948874' },
{ objectid: 555, userid: '2', associationid: '1950833' },
];
const myStr = '111*1*1968397,222*1*1968398,222*2*1968399,333*2*1968401,333*4*1968402,333*1*19684034';
const data = myStr.split(',')
.reduce((acc, e) => {
const [objectid, contactid, associationid] = e.split('*')
if (!globalLkupRemoveContactReviewer.find((item2) =>
item2.userid === contactid)) return acc // skip
const parent = acc.find(e => e.objectid === objectid)
const child = { isdelete: "1", contactid, associationid }
if (parent) {
parent.contacts.push(child) // append contact
} else {
acc.push({objectid,contacts: [child]}) // new object
}
return acc
}, [])
console.log(JSON.stringify(data, null, 2))
As a result, we do not have unnecessary actions and operations.
UPDATE
Another great example of how to improve performance with reduce
. The morbusg's answer has a use of Set
, but you can create it in different ways. I suggest creating it in reduce
- we will have one loop
. In the case of new Set(x.map(...))
we have a map loop
and an inner loop
in the Set constructor
.
const globalLkupRemoveContactReviewer = [
{ objectid: 555, userid: '1', associationid: '1948874' },
{ objectid: 555, userid: '2', associationid: '1950833' },
];
console.time('1')
for (let i=0; i<100; i++)
new Set(globalLkupRemoveContactReviewer.map(({userid}) => userid))
console.timeEnd('1')
console.time('2')
for (let i=0; i<100; i++)
globalLkupRemoveContactReviewer.reduce((acc, {userid}) => acc.has(userid) ? acc : acc.add(userid), new Set)
console.timeEnd('2')
The final version might look like this:
const globalLkupRemoveContactReviewer = [
{ objectid: 555, userid: '1', associationid: '1948874' },
{ objectid: 555, userid: '2', associationid: '1950833' },
];
const globalRemoveContactId = globalLkupRemoveContactReviewer
.reduce((acc, {userid}) => acc.has(userid) ? acc : acc.add(userid), new Set)
const myStr = '111*1*1968397,222*1*1968398,222*2*1968399,333*2*1968401,333*4*1968402,333*1*19684034';
const data = myStr.split(',')
.reduce((acc, e) => {
const [objectid, contactid, associationid] = e.split('*')
if (!globalRemoveContactId.has(contactid)) return acc // skip
const parent = acc.find(e => e.objectid === objectid)
const child = { isdelete: "1", contactid, associationid }
if (parent) {
parent.contacts.push(child) // append contact
} else {
acc.push({objectid,contacts: [child]}) // new object
}
return acc
}, [])
console.log(JSON.stringify(data, null, 2))
-
\$\begingroup\$ Hey I get item1 is not defined. \$\endgroup\$Karim Ali– Karim Ali2023年02月28日 19:03:50 +00:00Commented Feb 28, 2023 at 19:03
-
\$\begingroup\$ @KarimAli I've updated the answer with some more explanatory details. \$\endgroup\$Daniil Loban– Daniil Loban2023年03月02日 23:02:43 +00:00Commented Mar 2, 2023 at 23:02
-
\$\begingroup\$ Txs. Really Appreciated. \$\endgroup\$Karim Ali– Karim Ali2023年03月03日 14:47:19 +00:00Commented Mar 3, 2023 at 14:47
The most expensive part is likely the Array.prototype.find
inside the iteration, which can be remedied with a constant time lookup data structure such as a Set
or even just a plain object keyed by userid
:
const uniqUsers = new Set(globalLkupRemoveContactReviewer.map(({userid}) => userid))
and when filtering:
.filter (({userid}) => !uniqUsers.has(userid))
Please try to avoid such lengthy variables names as globalLkupRemoveContactReviewer
.
-
\$\begingroup\$ Hey, do you mind providing your version? \$\endgroup\$Karim Ali– Karim Ali2023年03月01日 19:35:55 +00:00Commented Mar 1, 2023 at 19:35