Input json:
const i = {
"38931": [{
"userT": "z",
"personId": 13424,
"user": {
"id": 38931,
"email": "sample",
},
},
{
"userType": "z",
"personId": 19999,
"user": {
"id": 38931,
"email": "sample",
},
}
],
"77777": [{
"userT": "z",
"personId": 55555,
"user": {
"id": 77777,
"email": "sample",
},
}]
}
desired output
{
"38931": {
"13424": {
"userT": "z",
"personId": 13424,
"user": {
"id": 38931,
"email": "sample"
}
},
"19999": {
"userType": "z",
"personId": 19999,
"user": {
"id": 38931,
"email": "sample"
}
}
},
"77777": {
"55555": {
"userT": "z",
"personId": 55555,
"user": {
"id": 77777,
"email": "sample"
}
}
}
}
This is what I tried to bring it to O(n)
, but still the destructuring in the reducer will give me O(n2) which is in the last .reducer
func with callback accObject
.
const i = {
"38931": [{
"userT": "z",
"personId": 13424,
"user": {
"id": 38931,
"email": "sample",
},
},
{
"userType": "z",
"personId": 19999,
"user": {
"id": 38931,
"email": "sample",
},
}
],
"77777": [{
"userT": "z",
"personId": 55555,
"user": {
"id": 77777,
"email": "sample",
},
}]
}
const accList = (acc, id) => {
acc.push(i[id]);
return acc;
}
const accObject = (acc, [key, val]) => {
const {
user: {
id
}
} = val;
acc[id] = {
...acc[id],
[key]: val
};
return acc;
}
// concat arrays of main object (i) 2D array, transform to 1D array,
// transform to hashMap with key personId,
// transform to array for iterable (Object.entries) and create the object result.
const personas = Object.keys(i)
.reduce(accList, [])
.flat()
.reduce((acc, obj) => {
acc[obj.personId] = obj;
return acc;
}, {});
const result =
Object
.entries(personas)
.reduce(accObject, {});
console.log('result', result);
It does give me the correct result, but am wondering if there is a bette approach to have
T = O(n)
CodePudding user response:
I think you can do this with a single iteration over the entries in the top-level object, converting the array of objects under each key into an object using Object.fromEntries
:
const i = {
"38931": [{
"userT": "z",
"personId": 13424,
"user": {
"id": 38931,
"email": "sample",
},
},
{
"userType": "z",
"personId": 19999,
"user": {
"id": 38931,
"email": "sample",
},
}
],
"77777": [{
"userT": "z",
"personId": 55555,
"user": {
"id": 77777,
"email": "sample",
},
}]
}
const result = Object.fromEntries(Object.entries(i)
.map(([k, v]) => [k,
Object.fromEntries(v.map(o => [o.personId, o]))
])
)
console.log(result)
.as-console-wrapper { max-height: 100% !important; top 0; }
If you don't mind modifying the object in place, you can use a simple forEach
:
const i = {
"38931": [{
"userT": "z",
"personId": 13424,
"user": {
"id": 38931,
"email": "sample",
},
},
{
"userType": "z",
"personId": 19999,
"user": {
"id": 38931,
"email": "sample",
},
}
],
"77777": [{
"userT": "z",
"personId": 55555,
"user": {
"id": 77777,
"email": "sample",
},
}]
}
Object.keys(i).forEach(k => i[k] = Object.fromEntries(i[k].map(o => [o.personId, o])))
console.log(i)
.as-console-wrapper { max-height: 100% !important; top 0; }
CodePudding user response:
I think this can be achieved just with some reduce
like this and it's compatible with all Browsers (even IE).
* Some checks can be added into the collectionToObject function to ensure that wanted property ('personId') is present in collection items to avoid loosing data under undefined
key.
const input = {
"38931": [{
"userT": "z",
"personId": 13424,
"user": {
"id": 38931,
"email": "sample",
},
},
{
"userType": "z",
"personId": 19999,
"user": {
"id": 38931,
"email": "sample",
},
}
],
"77777": [{
"userT": "z",
"personId": 55555,
"user": {
"id": 77777,
"email": "sample",
},
}]
}
/**
* @param collection {Array} - Collection to reduce into a mapped object
* @param propertyToKey {string} - Property for collection item value to use as object key
*/
function collectionToObject(collection, propertyToKey) {
return collection.reduce((accum, item) => {
accum[item[propertyToKey]] = item;
return accum;
}, {});
}
const result = Object.keys(input).reduce((accum, key) => {
accum[key] = collectionToObject(input[key], 'personId');
return accum;
}, {});
console.log(result);