Let's say we have an array of objects as below:
const example = [
{ id: "1", childIds: ["2"], parentId: "0" },
{ id: "2", childIds: ["3", "4"], parentId: "1" },
{ id: "3", childIds: [], parentId: "2" },
{ id: "4", childIds: ["5", "6"], parentId: "2" },
{ id: "5", childIds: [], parentId: "4" },
{ id: "6", childIds: [], parentId: "4" },
];
Problem: Copy this object, by generating new IDs.
IDs can be different ofc. Assume that we're using a 3rd party ID generator function to handle it. But the new IDs should match to keep the child-parent relation.
So, how would your JS function look like to solve this problem?
Expected result:
const copied = [
{ id: "10", childIds: ["20"], parentId: "0" },
{ id: "20", childIds: ["30", "40"], parentId: "10" },
{ id: "30", childIds: [], parentId: "20" },
{ id: "40", childIds: ["50", "60"], parentId: "20" },
{ id: "50", childIds: [], parentId: "40" },
{ id: "60", childIds: [], parentId: "40" },
];
This is what I tried (getting error: TypeError: Cannot assign to read only property 'parentId' of object '#')
const copied = [];
example.forEach((child) => {
const newId = generateId();
// check if this child is parent of other elements, then update parentIds
const childrenOfThisChild = example.filter(
(el) => el.parentId === child.id
);
if (childrenOfThisNode.length) {
childrenOfThisNode.forEach(
(child) => (child = { ...child, parentId: newId })
);
}
// check if this child is child of other elements, then update childIds
example.forEach((el) => {
const index = el.childIds.indexOf(child.id);
if (index !== -1) {
el.childIds[index] = newId;
}
});
// add the currently iterated object to new copied array
copied.push({ ...child, id: newId });
});
CodePudding user response:
You loop over the array once, changing all the ids of your objects (and saving what id changed to what in a lookup object). Then you loop again and change all teh childIds and parentIds based on your lookup object.
const example = [
{ id: "1", childIds: ["2"], parentId: null },
{ id: "2", childIds: ["3", "4"], parentId: "1" },
{ id: "3", childIds: [], parentId: "2" },
{ id: "4", childIds: ["5", "6"], parentId: "2" },
{ id: "5", childIds: [], parentId: "4" },
{ id: "6", childIds: [], parentId: "4" },
];
const newIds = [10, 20, 30, 40, 50, 60, 70]
//I'm just gonna make the assumption, that you are getting an array of unique IDs from the 3rd party
function replaceIds (array, idsArray) {
const lookup = {};
const retArr = array.map(obj => {return { ...obj }})
retArr.forEach((obj, index) => {
lookup[obj.id] = idsArray[index]
obj.id = idsArray[index]
})
retArr.forEach(obj => {
obj.parentId = lookup[obj.parentId] || null;
obj.childIds = obj.childIds.map(id => lookup[id])
})
return retArr
}
console.log(replaceIds(example, newIds))
If you have trouble with the requirement for a newIDs array. you can easily create one with some code like this:
const IdArray = newArray(example.length)
IdArray.map(x => generateId())
CodePudding user response:
You can try something like this:
function generateId() {
return Math.floor(Math.random() * 100) "";
}
const example = [
{ id: "1", childIds: ["2"], parentId: "0" },
{ id: "2", childIds: ["3", "4"], parentId: "1" },
{ id: "3", childIds: [], parentId: "2" },
{ id: "4", childIds: ["5", "6"], parentId: "2" },
{ id: "5", childIds: [], parentId: "4" },
{ id: "6", childIds: [], parentId: "4" },
];
var copied = [];
example.forEach((ex, i) => {
const parentId = i === 0 ? "0" : copied[parseInt(i / 2)].id;
copied.push({
id: generateId(),
childIds: Array.from({ length: ex.childIds.length }).map(() => generateId()),
parentId
});
});