搜索并修改深度嵌套的 javascript 对象
Search through and modify a deeply nested javascript object
我有一个对象,可以与对象、数组、对象数组等深度嵌套。
每个嵌套对象都有一个 sys
属性,后者又有一个 id
属性.
我有一个单独的 id
值列表,这些值对应于我想从原始对象中删除的对象。我怎样才能递归地遍历整个对象并将其修改为不再包含这些对象?
例如,假设我有以下数据:
let data = {
sys: {
id: '1'
},
items: [
{
sys: {
id: '2'
},
fields: {
title: 'Item title',
sponsor: {
sys: {
id: '3'
},
fields: {
title: 'Sponsor Title'
}
},
actions: [
{
sys: {
id: '4'
},
fields: {
title: 'Google',
url: 'google.com'
}
},
{
sys: {
id: '5'
},
fields: {
title: 'Yahoo',
url: 'yahoo.com'
}
}
]
}
}
]
}
然后我有一个 id
数组要删除:
const invalidIds = ['3', '5'];
在我 运行 函数之后,生成的对象应该将 属性 和 '3'
的 sys.id
设置为 null
,并且对象'5'
的 sys.id
应该简单地从其包含数组中删除:
// Desired Output:
{
sys: {
id: '1'
},
items: [
{
sys: {
id: '2'
},
fields: {
title: 'Item title',
sponsor: null,
actions: [
{
sys: {
id: '4'
},
fields: {
title: 'Google',
url: 'google.com'
}
}
]
}
}
]
}
在 this solution 的帮助下,我能够递归搜索对象及其各种嵌套数组:
const process = (key, value) => {
if (typeof value === 'object' && value.sys && value.sys.id && invalidIds.includes(value.sys.id)) {
console.log('found one', value.sys.id);
}
};
const traverse = (obj, func) => {
for (let key in obj) {
func.apply(this, [key, obj[key]]);
if (obj[key] !== null) {
if (typeof obj[key] === 'object') {
traverse(obj[key], func);
} else if (obj[key].constructor === Array) {
obj[key].map(item => {
if (typeof item === 'object') {
traverse(item, func);
}
});
}
}
}
};
traverse(data, process);
但是我不知道如何正确修改数组。此外,我更愿意创建一个全新的对象而不是修改现有的对象以保持不变。
以下是导致我的解决方案的观察结果:
- 要创建新对象,您需要在函数中的某处使用
return
。
- 要从数组中删除项目,您需要先过滤掉有效项目,然后对它们递归调用
traverse
。
typeof obj[key] === 'object'
即使对于 Array 也会 return 为真,所以
下一个 else if
块永远不会被击中。
至于实现,我的第一步是创建一个辅助 good
函数来检测无效对象。
good = (obj) =>{
try{return !(invalidIds.includes(obj.sys.id));}
catch(err){return true;}
}
现在主要traverse
-
traverse = (obj) => {
//I assumed when an object doesn't have 'sys' but have 'id', it must be sys obj.
if (obj==null) return null;
if(obj.constructor === Array) return obj.filter(good).map(traverse);
if(obj.sys==undefined) { //this checks if it's sys object.
if(obj.id!=undefined) return obj;
}
for (let key in obj) {
if (key!=0) {
if (good(obj[key])) {obj[key] = traverse(obj[key]);}
else {obj[key] = null;}
}
}
return obj;
};
对于Array对象,按照第2点,我先过滤掉有效的对象,然后映射它们进行遍历。在对象的情况下,=
运算符用于捕获有效的子对象,return 通过对 traverse
的递归调用编辑,而不是简单地修改它们。
注意:我几乎不知道javascript,但还是尝试了一下,因为这个递归问题相当普遍。所以要注意 JS 的特定问题。具体来说,如评论中所述,我对检查 'sys' 个对象的方式不满意。
我有一个对象,可以与对象、数组、对象数组等深度嵌套。
每个嵌套对象都有一个 sys
属性,后者又有一个 id
属性.
我有一个单独的 id
值列表,这些值对应于我想从原始对象中删除的对象。我怎样才能递归地遍历整个对象并将其修改为不再包含这些对象?
例如,假设我有以下数据:
let data = {
sys: {
id: '1'
},
items: [
{
sys: {
id: '2'
},
fields: {
title: 'Item title',
sponsor: {
sys: {
id: '3'
},
fields: {
title: 'Sponsor Title'
}
},
actions: [
{
sys: {
id: '4'
},
fields: {
title: 'Google',
url: 'google.com'
}
},
{
sys: {
id: '5'
},
fields: {
title: 'Yahoo',
url: 'yahoo.com'
}
}
]
}
}
]
}
然后我有一个 id
数组要删除:
const invalidIds = ['3', '5'];
在我 运行 函数之后,生成的对象应该将 属性 和 '3'
的 sys.id
设置为 null
,并且对象'5'
的 sys.id
应该简单地从其包含数组中删除:
// Desired Output:
{
sys: {
id: '1'
},
items: [
{
sys: {
id: '2'
},
fields: {
title: 'Item title',
sponsor: null,
actions: [
{
sys: {
id: '4'
},
fields: {
title: 'Google',
url: 'google.com'
}
}
]
}
}
]
}
在 this solution 的帮助下,我能够递归搜索对象及其各种嵌套数组:
const process = (key, value) => {
if (typeof value === 'object' && value.sys && value.sys.id && invalidIds.includes(value.sys.id)) {
console.log('found one', value.sys.id);
}
};
const traverse = (obj, func) => {
for (let key in obj) {
func.apply(this, [key, obj[key]]);
if (obj[key] !== null) {
if (typeof obj[key] === 'object') {
traverse(obj[key], func);
} else if (obj[key].constructor === Array) {
obj[key].map(item => {
if (typeof item === 'object') {
traverse(item, func);
}
});
}
}
}
};
traverse(data, process);
但是我不知道如何正确修改数组。此外,我更愿意创建一个全新的对象而不是修改现有的对象以保持不变。
以下是导致我的解决方案的观察结果:
- 要创建新对象,您需要在函数中的某处使用
return
。 - 要从数组中删除项目,您需要先过滤掉有效项目,然后对它们递归调用
traverse
。 typeof obj[key] === 'object'
即使对于 Array 也会 return 为真,所以 下一个else if
块永远不会被击中。
至于实现,我的第一步是创建一个辅助 good
函数来检测无效对象。
good = (obj) =>{
try{return !(invalidIds.includes(obj.sys.id));}
catch(err){return true;}
}
现在主要traverse
-
traverse = (obj) => {
//I assumed when an object doesn't have 'sys' but have 'id', it must be sys obj.
if (obj==null) return null;
if(obj.constructor === Array) return obj.filter(good).map(traverse);
if(obj.sys==undefined) { //this checks if it's sys object.
if(obj.id!=undefined) return obj;
}
for (let key in obj) {
if (key!=0) {
if (good(obj[key])) {obj[key] = traverse(obj[key]);}
else {obj[key] = null;}
}
}
return obj;
};
对于Array对象,按照第2点,我先过滤掉有效的对象,然后映射它们进行遍历。在对象的情况下,=
运算符用于捕获有效的子对象,return 通过对 traverse
的递归调用编辑,而不是简单地修改它们。
注意:我几乎不知道javascript,但还是尝试了一下,因为这个递归问题相当普遍。所以要注意 JS 的特定问题。具体来说,如评论中所述,我对检查 'sys' 个对象的方式不满意。