如何用另一个对象的键动态替换一个对象中的某些键? [英] How can I dynamically replace certain keys in one object with keys from another object?
问题描述
我有两个对象代表两种不同语言的翻译.它们在结构上完全相同,但值已被翻译.
I have two objects that represent translations for two different languages. They are exactly the same in structure but the values have been translated.
英语
{
about: {
title: "About",
subtitle: "Something",
table: {
columns: [...],
}
},
products: {
columns: [...]
},
games: {
details: {
title: "Game Details",
columns: [...]
}
}
}
法语
{
about: {
title: "À propos de",
subtitle: "Quelque chose",
table: {
columns: [...],
}
},
products: {
columns: [...]
},
games: {
details: {
title: "Détails du jeu",
columns: [...]
}
}
}
我想按原样保留法语对象,但将 columns
的所有实例替换为第一个对象的英文版本.我该怎么做?
I want to retain the French object as is, but replace all instances of columns
with the English version from the first object. How can I do that?
我使用的对象很大而且嵌套很深,所以我想我需要某种递归函数.不过,我不确定如何跟踪要替换的键.
The objects I'm using are quite big and deeply nested, so I imagine I need some kind of recursive function. I'm not sure how I can keep track of which key I'm on to do the replacement though.
推荐答案
具体例子
首先我们建立一个定义良好的例子,为en
列填充一些值 -
First we establish a well-defined example, filling in some values for en
columns -
let en =
{
about: {
title: "About",
subtitle: "Something",
table: {
columns: ["en_about_1", "en_about_2"] // <-
}
},
products: {
columns: ["en_products"] // <-
},
games: {
details: {
title: "Game Details",
columns: ["en_games_1", "en_games_2"] // <-
}
}
}
我们对 fr
做同样的事情 -
And we do the same for fr
-
let fr =
{
about: {
title: "À propos de",
subtitle: "Quelque chose",
table: {
columns: ["fr_apropos_1", "fr_apropos_2"], // <-
}
},
products: {
columns: ["fr_produit"] // <-
},
games: {
details: {
title: "Détails du jeu",
columns: ["fr_details_1", "fr_details_2"] // <-
}
}
}
遍历
接下来我们需要一种遍历给定对象中所有paths
的方法 -
Next we need a way to traverse all paths
in a given object -
function* paths (t)
{ switch(t?.constructor)
{ case Object:
for (const [k,v] of Object.entries(t))
for (const path of paths(v))
yield [k, ...path]
break
default:
yield []
}
}
let fr =
{about: {title: "À propos de",subtitle: "Quelque chose",table: {columns: ["fr_apropos_1", "fr_apropos_2"],}},products: {columns: ["fr_produit"]},games: {details: {title: "Détails du jeu",columns: ["fr_details_1", "fr_details_2"]}}}
for (const path of paths(fr))
console.log(JSON.stringify(path))
["about","title"]
["about","subtitle"]
["about","table","columns"]
["products","columns"]
["games","details","title"]
["games","details","columns"]
读写
接下来我们需要一种从一个对象向另一个对象读取和写入值的方法 -
Next we'll need a way to read and write values from one object to another -
getAt
接受一个对象和一个路径,并返回一个值setAt
接受一个对象、一个路径和一个值,并设置一个值
getAt
which takes an object and a path, and returns a valuesetAt
which takes an object, a path, and a value, and sets a value
function getAt (t, [k, ...path])
{ if (k == null)
return t
else
return getAt(t?.[k], path)
}
function setAt (t, [k, ...path], v)
{ if (k == null)
return v
else
return {...t, [k]: setAt(t?.[k] ?? {}, path, v) }
}
复制到路径
对于fr
的每个path
,路径以columns"
结尾,更新fr
在path
的值来自 en
在 path
-
For each path
of fr
, where the path ends in "columns"
, update fr
at path
with the value from en
at path
-
for (const path of paths(fr)) // for each path of fr
if (path.slice(-1)[0] == "columns") // where the path ends in "columns"
fr = setAt(fr, path, getAt(en, path)) // update fr at path with value from en at path
console.log(JSON.stringify(fr))
展开下面的代码片段并在您自己的浏览器中验证结果 -
Expand the snippet below and verify the results in your own browser -
function* paths (t)
{ switch(t?.constructor)
{ case Object:
for (const [k,v] of Object.entries(t))
for (const path of paths(v))
yield [k, ...path]
break
default:
yield []
}
}
function getAt (t, [k, ...path])
{ if (k == null)
return t
else
return getAt(t?.[k], path)
}
function setAt (t, [k, ...path], v)
{ if (k == null)
return v
else
return {...t, [k]: setAt(t?.[k] ?? {}, path, v) }
}
let en =
{about: {title: "About",subtitle: "Something",table: {columns: ["en_about_1", "en_about_2"]}},products: {columns: ["en_products"]},games: {details: {title: "Game Details",columns: ["en_games_1", "en_games_2"]}}}
let fr =
{about: {title: "À propos de",subtitle: "Quelque chose",table: {columns: ["fr_apropos_1", "fr_apropos_2"],}},products: {columns: ["fr_produit"]},games: {details: {title: "Détails du jeu",columns: ["fr_details_1", "fr_details_2"]}}}
for (const path of paths(fr))
if (path.slice(-1)[0] == "columns")
fr = setAt(fr, path, getAt(en, path))
console.log(JSON.stringify(fr, null, 2))
{
"about": {
"title": "À propos de",
"subtitle": "Quelque chose",
"table": {
"columns": [ // <-
"en_about_1",
"en_about_2"
]
}
},
"products": {
"columns": [ // <-
"en_products"
]
},
"games": {
"details": {
"title": "Détails du jeu",
"columns": [ // <-
"en_games_1",
"en_games_2"
]
}
}
}
将所有 en
值复制到每个 列"
的 fr
.
All en
values are copied to fr
for each "columns"
.
这篇关于如何用另一个对象的键动态替换一个对象中的某些键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!