javascript - Deep map/transform js object with ability to alter keys and values
问题描述
I've seen lots of solutions for "deep mapping" over an object to change either the keys of the object, or the value of the object, but not both.
For example if given the following object:
const obj = {
this: {
is_not: {
something: "we want to keep"
},
is: {
a: {
good_idea: 22
},
b: {
bad_idea: 67
},
c: [{
meh_idea: 22
}]
}
}
}
Essentially I'd like to be able to transform it with the following function signature:
const newObj = deepTransform(obj, iterator)
function iterator (key, value) {
if (key.endsWith("idea")) return { [key.replace("idea", "")]: value + 1}
else if (key === "is_not") return {}
else return {[key]: value}
}
Running deepTransform would result in an object that looks like:
{
this: {
is: {
a: {
good: 23
},
b: {
bad: 68
},
c: [{
meh: 23
}]
}
}
}
If anyone could help me create this function that would be awesome! I'd be more than happy if it used lodash functions under the hood.
Please ask if anything is unclear. Thanks!
解决方案
You can use lodash's _.transform()
to recursively iterate objects/arrays, and rebuild them with updated keys and values:
const { transform, toPairs, isObject } = _
const deepTransform = (obj, iterator) => transform(obj, (acc, val, key) => {
const pair = toPairs(iterator(key, val))[0] // use the iterator and get a pair of key and value
if(!pair) return // if pair is undefined, continue to next iteration
const [k, v] = pair // get the update key and value from the pair
// set the updated key and value, and if the value is an object iterate it as well
acc[k] = isObject(v) ? deepTransform(v, iterator) : v
})
const obj = {"this":{"is_not":{"something":"we want to keep"},"is":{"a":{"good_idea":22},"b":{"bad_idea":67},"c":[{"meh_idea":22}]}}}
const iterator = (key, value) => {
if (String(key).endsWith("_idea")) return { [key.replace("_idea", "")]: value + 1}
if (key === "is_not") return {}
return {[key]: value}
}
const newObj = deepTransform(obj, iterator)
console.log(newObj)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
Changing the iterator a to return a pair of [key, value], would make _.toPairs()
redundant, and would simplify the code:
const { transform, isObject, isUndefined } = _
const deepTransform = (obj, iterator) => transform(obj, (acc, val, key) => {
const [k, v] = iterator(key, val) // use the iterator and get a pair of key and value
if(isUndefined(k)) return // skip if no updated key
// set the updated key and value, and if the value is an object iterate it as well
acc[k] = isObject(v) ? deepTransform(v, iterator) : v
})
const obj = {"this":{"is_not":{"something":"we want to keep"},"is":{"a":{"good_idea":22},"b":{"bad_idea":67},"c":[{"meh_idea":22}]}}}
const iterator = (key, value) => {
if (String(key).endsWith("_idea")) return [key.replace("_idea", ""), value + 1]
if (key === "is_not") return []
return [key, value]
}
const newObj = deepTransform(obj, iterator)
console.log(newObj)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
推荐阅读
- django - 如何将 keycloak 与 django 和 angular 集成
- r - 如何调试 FactoInvestigate 错误:无法打开连接
- python-3.x - 使用 np.append() 在数组中形成数组
- c# - 时间:2019-04-01 标签:c#keep running application without run
- python - 如何检查熊猫数据框中是否存在特定条目并添加新条目?
- c# - 如何在 C# 代码中为 POST 方法创建精确的 JSON 格式?
- firebase - 侦听查询中第一个元素的 Firestore 安全规则
- google-cloud-platform - gcloud:显示 SimulateMaintenanceEvent 的配额限制
- javascript - 用于 6.3 到 6.5 AEM 升级的迁移工作流模型和脚本,脚本没有被拾取
- java - 如何将字符串返回为json格式