Reputation: 373
I have a multidimentionnal array and i want to rename property recursevly, i've tried this function
const newMenu =
Array.isArray(copyMenu) &&
copyMenu.length > 0 &&
copyMenu.map(({ families: children, id: key, label: title, ...rest }) => ({
key,
title,
...rest,
children,
}));
But it rename just the big array, not the properties inside table property This is my input array :
const input = [
{
id: 9040,
label: "33",
tables: [
{
id: 8957,
label: "THB_Adresse_Famille",
idFather: 8957,
tableIsFamily: false,
tables: []
},
{
id: 8941,
label: "THB_Contact_Famille",
idFather: 8941,
tableIsFamily: false,
tables: [
{ id: 8947, label: "THB_Contact_Table", idFather: 8941 },
{ id: 9855, label: "THB_Contact_Table_BIS", idFather: 8941 }
]
},
{
id: 8949,
label: "THB_Societe_Famille",
idFather: 8949,
tableIsFamily: false,
tables: []
},
{
id: 8983,
label: "THB_TELEPHONE",
idFather: 8983,
tableIsFamily: false,
tables: []
},
{
id: 10070,
label: "THB_TEST_5708",
idFather: 10070,
tableIsFamily: false,
tables: []
}
]
},
{
id: 9761,
label: "1111111",
tables: [
{
id: 9742,
label: "RRA PROTOCOLE",
idFather: 9742,
tableIsFamily: false,
tables: []
},
{
id: 9753,
label: "RRA TEST CASE LINE",
idFather: 9753,
tableIsFamily: false,
tables: []
}
]
},
]
The output should be ike this :
const output = [
{
key: 9040,
title: "33",
children: [
{
key: 8957,
title: "THB_Adresse_Famille",
idFather: 8957,
tableIsFamily: false,
children: []
},
{
key: 8941,
title: "THB_Contact_Famille",
idFather: 8941,
tableIsFamily: false,
children: [
{ key: 8947, title: "THB_Contact_Table", idFather: 8941 },
{ key: 9855, title: "THB_Contact_Table_BIS", idFather: 8941 }
]
},
{
key: 8949,
title: "THB_Societe_Famille",
idFather: 8949,
tableIsFamily: false,
children: []
},
{
key: 8983,
title: "THB_TELEPHONE",
idFather: 8983,
tableIsFamily: false,
children: []
},
{
key: 10070,
title: "THB_TEST_5708",
idFather: 10070,
tableIsFamily: false,
children: []
}
]
},
{
key: 9761,
title: "1111111",
children: [
{
key: 9742,
title: "RRA PROTOCOLE",
idFather: 9742,
tableIsFamily: false,
children: []
},
{
key: 9753,
title: "RRA TEST CASE LINE",
idFather: 9753,
tableIsFamily: false,
children: []
}
]
},
]
I'v searched on stackoverflow but i don't found any solutions to this case, any help will be appreciated. Thank you
Upvotes: 0
Views: 62
Reputation: 3691
Looks like a number of good answers have been provided. Here's one potential implementation to achieve the desired objective:
Sample Code
const replacePropsMap = {
id: 'key',
label: 'title',
tables: 'children'
};
const renameProps = (arr = inputArr, propsMap = replacePropsMap) => (
arr.reduce((fin, itm) => ([
...fin,
{
...(
Object.entries(itm).reduce((fin2, itm2) => ({
...fin2,
...(
itm2[0] in propsMap
? { [propsMap[itm2[0]]]: itm2[1] }
: {}
)
}), {})
),
children: itm && itm.tables && itm.tables.length > 0
? renameProps(itm.tables)
: []
}
]), [])
);
Explanation
.reduce
to iterate through the array (with the aggregator as fin
and each item as itm
)...
spread-operator to first place existing items (from past iterations)itm
, use Object.entries()
and .reduce
to filter-out id
, label
, tables
props, but retain all other propskey
, title
to hold values of id
, label
respectivelytables
array (if it exists) and store the result in children
prop.Code Snippet
const inputArr = [{
id: 9040,
label: "33",
tables: [
{
id: 8957,
label: "THB_Adresse_Famille",
idFather: 8957,
tableIsFamily: false,
tables: []
},
{
id: 8941,
label: "THB_Contact_Famille",
idFather: 8941,
tableIsFamily: false,
tables: [
{ id: 8947, label: "THB_Contact_Table", idFather: 8941 },
{ id: 9855, label: "THB_Contact_Table_BIS", idFather: 8941 }
]
},
{
id: 8949,
label: "THB_Societe_Famille",
idFather: 8949,
tableIsFamily: false,
tables: []
},
{
id: 8983,
label: "THB_TELEPHONE",
idFather: 8983,
tableIsFamily: false,
tables: []
},
{
id: 10070,
label: "THB_TEST_5708",
idFather: 10070,
tableIsFamily: false,
tables: []
}
]
}, {
id: 9761,
label: "1111111",
tables: [
{
id: 9742,
label: "RRA PROTOCOLE",
idFather: 9742,
tableIsFamily: false,
tables: []
},
{
id: 9753,
label: "RRA TEST CASE LINE",
idFather: 9753,
tableIsFamily: false,
tables: []
}
]
}
];
const replacePropsMap = {
id: 'key',
label: 'title',
tables: 'children'
};
const renameProps = (arr = inputArr) => (
arr.reduce((fin, itm) => ([
...fin,
{
...(
Object.entries(itm).reduce((fin2, itm2) => ({
...fin2,
...(
itm2[0] in replacePropsMap
? { [replacePropsMap[itm2[0]]]: itm2[1] }
: {}
)
}), {})
),
children: itm && itm.tables && itm.tables.length > 0
? renameProps(itm.tables)
: []
}
]), [])
);
console.log(renameProps());
Upvotes: 0
Reputation: 21
I see your attempted solution is lacking the recursive call you say you want to implement. It may be a little tricky to conceive. You essentially need to wrap the repeating code in a function.
const recurse = (input) =>
input?.map(({ tables, id, label, ...rest }) =>
({ children: recurse(tables), key: id, title: label, ...rest }))
Then, notice the function calls itself on the relevant part, a.k.a. the general case. Also not unimportantly, the function needs to know when to stop, i.e. when it has hit the base case. Without checking for the base case you will quickly find out where this website gets its name from. In the example above I did apply optional chaining so it is a bit subtle.
Edit: with regard to destructuring, there are roughly two equivalent approaches (as far as I can see), here is the other which matches more with your initial approach:
const recurse = (input) =>
input?.map(({ tables, id: key, label: title, ...rest }) =>
({ children: recurse(tables), key, title, ...rest }))
Upvotes: 1
Reputation: 2679
A potential solution could be:
const input = [{
id: 9040,
label: "33",
tables: [{
id: 8957,
label: "THB_Adresse_Famille",
idFather: 8957,
tableIsFamily: false,
tables: []
},
{
id: 8941,
label: "THB_Contact_Famille",
idFather: 8941,
tableIsFamily: false,
tables: [{
id: 8947,
label: "THB_Contact_Table",
idFather: 8941
},
{
id: 9855,
label: "THB_Contact_Table_BIS",
idFather: 8941
}
]
},
{
id: 8949,
label: "THB_Societe_Famille",
idFather: 8949,
tableIsFamily: false,
tables: []
},
{
id: 8983,
label: "THB_TELEPHONE",
idFather: 8983,
tableIsFamily: false,
tables: []
},
{
id: 10070,
label: "THB_TEST_5708",
idFather: 10070,
tableIsFamily: false,
tables: []
}
]
},
{
id: 9761,
label: "1111111",
tables: [{
id: 9742,
label: "RRA PROTOCOLE",
idFather: 9742,
tableIsFamily: false,
tables: []
},
{
id: 9753,
label: "RRA TEST CASE LINE",
idFather: 9753,
tableIsFamily: false,
tables: []
}
]
},
];
function updateKeys(arr) {
return arr.map(({
tables,
id: key,
label: title,
...rest
}) => {
const children = Array.isArray(tables) && tables.length > 0 ? updateKeys(tables) : tables;
return {
key,
title,
children,
...rest
}
});
}
const output = updateKeys(input);
console.log(output);
Upvotes: -1
Reputation: 22564
You can use recursive approach to rename your keys by maintaining a lookup for renamed keys and recursively calling your function for array values.
const input = [ { id: 9040, label: "33", tables: [ { id: 8957, label: "THB_Adresse_Famille", idFather: 8957, tableIsFamily: false, tables: [] }, { id: 8941, label: "THB_Contact_Famille", idFather: 8941, tableIsFamily: false, tables: [ { id: 8947, label:"THB_Contact_Table", idFather: 8941 }, { id: 9855, label: "THB_Contact_Table_BIS", idFather: 8941 } ] }, { id: 8949, label: "THB_Societe_Famille", idFather: 8949, tableIsFamily: false, tables: [] }, { id: 8983, label: "THB_TELEPHONE", idFather: 8983, tableIsFamily: false, tables: [] }, { id: 10070, label: "THB_TEST_5708", idFather: 10070, tableIsFamily: false, tables: [] } ] }, { id: 9761, label: "1111111", tables: [ { id: 9742, label: "RRA PROTOCOLE", idFather: 9742, tableIsFamily: false, tables: [] }, { id: 9753, label: "RRA TEST CASE LINE", idFather: 9753, tableIsFamily: false, tables: [] } ] }, ],
keys = { id: 'key', label: 'title', tables: 'children'},
rename = (arr) => {
return arr.map(o => {
return Object.fromEntries(Object.keys(o).map(k => {
const key = keys[k] || k;
const value = Array.isArray(o[k]) ? rename(o[k]) : o[k];
return [key, value];
}));
});
};
console.log(rename(input));
Upvotes: 2