So I have an object like so that contains properties that are either and object (containing other objects untill it's not an object anymore) or an array of strings of text from english and french:
let langs = {
click : ["Click here", "Cliquez ici"],
stat : ["Fonction status", "Status de la fonction"],
no : ["Disabled", "Désactivé"],
ping : {
base : ["Pinging...", "Calcul du ping..."],
result : ["Search complete, my latency is", "Recherche terminée, ma latence est de"]
},
kick : {
error : {
msg: [
"I can't find this member, please check its writing or @!",
"Je n'ai pas trouvé ce membre, veuillez vérifier son orthographe ou son @ !"
]
}
}
}
And the output I expect is :
let langs = {
click : "Click here",
stat : "Fonction status",
no : "Disabled",
ping : {
base : "Pinging...",
result : "Search complete, my latency is"
},
kick : {
error : {
msg : "I can't find this member, please check its writing or @!"
}
}
}
My question : Is there a way to dynamically copy that object so that my output would be the exact same but with the arrays only be a string which is either the first or second element? I know how to set an object's property to (for example) the first element
let langs = { a : ["1","2"], b : ["3","4"] }
Object.keys(langs).forEach(n =>{
langs[n] = langs[n][0]
})
console.log(langs)
But the object "langs" can not only be an array but also an object containing arrays or objects containing objects of arrays etc.. Would be awesome to have a function for this..
let langs = { a : ["1","2"], b : ["3","4"] };
langs = onlySelectIndexElement(langs,0) // Or 1 if I want the second element etc..
CodePudding user response:
This is one of those cases where the built-in JSON library makes things a literal one liner:
let result = JSON.parse(JSON.stringify(langs, (key, value) =>
value instanceof Array ? value[0] : value
));
And presto, we are done. The reason this works is because of the little known second argument to JSON.stringify
, called the replacer function. We use that to just turn every array into "the first element in that array", and that's all we have to do. JSON.stringify
does the actual recursive object walking for us.
CodePudding user response:
You'd want a recursive function for this.
Map over the entries. If the value is an array, return the index. Otherwise, recursively run the value through the same function.
const onlySelectIndexElement = (obj, index) =>
Object.fromEntries(
Object.entries(obj).map(([ key, val ]) => [
key,
Array.isArray(val) ? val[index] : onlySelectIndexElement(val, index)
])
)
const langs = {"click":["Click here","Clique ici"],"stat":["Fonction status","Status de la fonction"],"no":["Disabled","Désactivé"],"ping":{"base":["Pinging...","Calcul du ping..."],"result":["Search complete, my latency is","Recherche terminée, ma latence est de"]},"kick":{"error":{"msg":["I can't find this member, please check its writing or @!","Je n'est pas trouvé ce membre, veuillez vérifier son écriture ou son @ !"]}}}
console.log("en", onlySelectIndexElement(langs, 0))
console.log("fr", onlySelectIndexElement(langs, 1))
.as-console-wrapper { max-height: 100% !important; }
CodePudding user response:
Use a recursive function that returns the first element of the array when the value is an array, otherwise returns a new object where the property values are recursive calls to the function.
let langs = {
click: ["Click here", "Clique ici"],
stat: ["Fonction status", "Status de la fonction"],
no: ["Disabled", "Désactivé"],
ping: {
base: ["Pinging...", "Calcul du ping..."],
result: ["Search complete, my latency is", "Recherche terminée, ma latence est de"]
},
kick: {
error: {
msg: [
"I can't find this member, please check its writing or @!",
"Je n'est pas trouvé ce membre, veuillez vérifier son écriture ou son @ !"
]
}
}
}
function mycopy(obj) {
if (Array.isArray(obj)) {
return obj[0];
}
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, mycopy(value)]));
}
console.log(mycopy(langs));