如何用另一个对象的键动态替换一个对象中的某些键? [英] How can I dynamically replace certain keys in one object with keys from another object?

查看:68
本文介绍了如何用另一个对象的键动态替换一个对象中的某些键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个对象代表两种不同语言的翻译.它们在结构上完全相同,但值已被翻译.

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 -

  1. getAt 接受一个对象和一个路径,并返回一个值
  2. setAt 接受一个对象、一个路径和一个值,并设置一个值
  1. getAt which takes an object and a path, and returns a value
  2. setAt 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"结尾,更新frpath 的值来自 enpath -

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆