这基本上是逻辑问题,应该适用于任何编程语言,我恰好为此使用了JavaScript
基本上想象我有某种类似的物体
{Props:"stuff",
other: {
stuff: "etc",
other: {
Extra: "filler",
other: {}
}
}
}
从本质上讲,是一个具有一些未知数量的额外属性的对象,但是每个子对象都有一个嵌套的属性,且名称相同(在本例中为“ other”),并且深度可能是无限的,这意味着可能存在根对象内有n个对象,每个子对象是另一个对象中容器的容器,这些对象的键是相同的(在本例中也是“ other”)
听起来可能比它复杂,但是基本上其他属性在根对象中嵌套并重复
我要成为一个函数,以给定深度(n)断开此嵌套链,从而将所有其他嵌套对象设置为一个值
这听起来似乎很复杂,但基本上,在上面的示例中,对象的“ other”属性的嵌套深度为3,假设我要在深度索引2处打破深度,从而将对象更改为具有一个嵌套的“其他”属性,设置为某个值(例如数字或字符串,例如说“ 5”),而不是设置为还包含另一个属性(以及可能的其他属性等)的另一个对象
那么我该如何制作一个函数,以接收一个包含未知数量的嵌套属性Ruth键k
的基础对象,并使其返回一个新对象(或修改原始对象,但我更喜欢只是返回一个与基础对象几乎相同的新对象,只是深度索引为n
时,键为k
的嵌套属性将被设置为值v
,而不是继续在它的嵌套深度未知数量的链中
我什至不知道该怎么做,我总是回到设置索引k
等于根函数的属性,但是将属性本身作为参数传递来代替原始根对象(基本上是递归的),除非输入对象不包含属性k
,在这种情况下,仅返回属性本身,但这只是一种递归方法,用于返回最内层的嵌套属性,但会造成损失适合实现上述结果的方法,这又是一个与基础对象Ruth几乎相同的新对象,但其嵌套属性的例外是深度为k
的键n
设置为value v
,甚至从哪里开始都完全茫然
答案 0 :(得分:2)
我们可以在这里使用递归函数
let obj = {Props:"stuff",
other: {
stuff: "etc",
other: {
Extra: "filler",
other: {
stuff: "abc",
other:{
stuff: "acbh",
other: {}
}
}
}
}
};
function normalizeObjectDepth(obj, level, curr_level, key){
if(curr_level==level-1){
obj.other = key;
return;
}
normalizeObjectDepth(obj.other, level, curr_level+1, key);
}
normalizeObjectDepth(obj, 3, 0, 5);
console.log(obj);
答案 1 :(得分:2)
您可以使用reduce
方法创建递归函数,该方法将检查当前递归级别是否小于目标递归级别,并在此基础上继续递归或将值设置为所需的递归级别。
const data = {
Props: "stuff",
other: {
stuff: "etc",
other: {
Extra: "filler",
other: {}
}
}
}
function modify(obj, key, lvl, val, clvl = 0) {
return Object.entries(obj).reduce((r, [k, v]) => {
if (k === key) {
if (clvl < lvl) {
r[k] = modify(v, key, lvl, val, clvl + 1)
} else {
r[k] = val
}
} else {
r[k] = v;
}
return r;
}, {})
}
const result = modify(data, 'other', 2, 'my value');
console.log(result)
具有简单for...in
循环的解决方案。
const data = {
Props: "stuff",
other: {
stuff: "etc",
other: {
Extra: "filler",
other: {
random: 'foo',
other: 'random'
}
}
}
}
function modify(obj, key, lvl, val, clvl = 0) {
const result = {}
for (let k in obj) {
if (k === key) {
if (clvl < lvl) {
result[k] = modify(obj[k], key, lvl, val, clvl + 1)
} else {
result[k] = val
}
} else {
result[k] = obj[k]
}
}
return result
}
const result = modify(data, 'other', 2, 'random');
console.log(result)
答案 2 :(得分:2)
这确保了深度克隆,因此原始对象不会更改。唯一的“高级”部分是JSON.parse(JSON.stringify(...)),但是可以用任何深层复制方法代替,或者您可以在使用函数之前简单地进行深层复制
const modifyNthKey = (obj, key, value, n) => {
let i = 0
let newObj = JSON.parse(JSON.stringify(obj))
let tmpObj = newObj
while (i < n) {
console.log('typeof: ' + typeof tmpObj[`${key}`])
if (typeof tmpObj[`${key}`] !== 'object') {
throw Error('unable to access key. Parent not object')
}
tmpObj = tmpObj[`${key}`]
i++
}
tmpObj[`${key}`] = value
return newObj
}
答案 3 :(得分:1)
这是一个相当简单的递归版本。它不会改变您的输入,但会返回一个新结构:
const modify = (obj, key, value, depth) => ({
...obj,
[key]: depth <= 0 ? value : modify (obj [key], key, value, depth - 1)
})
const data = {Props: "stuff", other: {stuff: "etc", other: {Extra: "filler", other: {}}}}
console .log (modify (data, 'other', 'new value', 2))
//~> {Props: "stuff", other: {stuff: "etc", other: {Extra: "filler", other:"new value"}}}
console .log (modify (data, 'other', 'new value', 1))
//~> {Props: "stuff", other: {stuff: "etc", other: "new value"}}
console .log (modify (data, 'other', 'new value', 0))
//~> {Props: "stuff", other: "new value"}
.as-console-wrapper {max-height: 100% !important; top: 0}
基本上,我们只是复制对象,将目标属性('other'
)设置为新值(如果我们位于递归的末尾,当depth
为0时)或结果object[key]
和depth -1
进行递归调用(否则)。
请注意,我们没有进行完全克隆,因此其他节点可能会通过引用共享。