遍历一个 object 获取密钥和所有 parents 密钥
Traversing an object getting the key and all parents keys
遍历树(json),使用JS实现getKeys(data, str)函数。获取密钥和所有 parents 个密钥。
const data = {
key1: 'str1',
key2: {
key3: 'str3',
key4: 'str4',
key5: {
key6: 'str6',
key7: 'str7',
key8: 'str8',
},
}
}
例如:
getKeys(数据,'str1');
return: 'key1'
getKeys(数据,'str3');
return: 'key2, key3'
getKeys(数据,'str6');
return: 'key2, key5, key6'
我认为可以通过递归来完成,但是怎么做呢?
这是我的解决方案,但失败了
let s = [];
function getKeys(data, str, key='') {
if (key !== '') {
s.push(key);
}
for (item in data) {
if (typeof data[item] === 'object') {
getKeys(data[item], str, item);
} else if (data[item] === str) {
s.push(item);
return s;
}
}
return s;
}
您的代码的问题在于它无条件地填充 "found" 列表,无论该值是否实际上在当前处理的分支下。考虑例如:
data = {
a: 1,
b: {
c: 2
},
d: {
e: {
e1: 3,
e2: 33,
},
f: {
f1: 4,
f2: 44,
},
}
};
执行getKeys(data, 44)
时,return将是[ 'b', 'd', 'e', 'f', 'f2' ]
,这是不正确的。
您需要做的是检查该值是否确实在当前节点下,只有在答案为是时才添加当前键。示例:
function getKeys(obj, val) {
if (!obj || typeof obj !== 'object')
return;
for (let [k, v] of Object.entries(obj)) {
if (v === val)
return [k];
let path = getKeys(v, val);
if (path)
return [k, ...path];
}
}
假设您只搜索 string
键,我们可以使用递归和回溯来检查键的子对象是否具有指定值。
如果有,则在我们的最终搜索字符串中添加父键。
为此,我使用 Object.entries()
遍历每对 [key, value]
并使用 Array.prototype.reduce()
累积结果:
var data = {
key1: 'str1',
key2: {
key3: 'str3',
key4: 'str4',
key5: {
key6: 'str6',
key7: 'str7',
key8: 'str8',
},
}
}
function getKeys(data, key, acc){
return Object.entries(data).reduce((acc, ele, idx) => {
if(ele.includes(key) && typeof ele[1] === "string"){
acc.push(ele[0]);
}
if(typeof ele[1] === "object" && !Array.isArray(ele[1]) && !(ele[1] instanceof Date)){
let old = acc.slice();
getKeys(ele[1], key, acc);
if(old.length !== acc.length){
acc.unshift(ele[0]);
}
}
return acc;
}, acc).join(" ");
}
console.log(getKeys(data, 'str1', []));
console.log(getKeys(data, 'str3', []));
console.log(getKeys(data, 'str6', []));
遍历树(json),使用JS实现getKeys(data, str)函数。获取密钥和所有 parents 个密钥。
const data = {
key1: 'str1',
key2: {
key3: 'str3',
key4: 'str4',
key5: {
key6: 'str6',
key7: 'str7',
key8: 'str8',
},
}
}
例如:
getKeys(数据,'str1'); return: 'key1'
getKeys(数据,'str3'); return: 'key2, key3'
getKeys(数据,'str6'); return: 'key2, key5, key6'
我认为可以通过递归来完成,但是怎么做呢?
这是我的解决方案,但失败了
let s = [];
function getKeys(data, str, key='') {
if (key !== '') {
s.push(key);
}
for (item in data) {
if (typeof data[item] === 'object') {
getKeys(data[item], str, item);
} else if (data[item] === str) {
s.push(item);
return s;
}
}
return s;
}
您的代码的问题在于它无条件地填充 "found" 列表,无论该值是否实际上在当前处理的分支下。考虑例如:
data = {
a: 1,
b: {
c: 2
},
d: {
e: {
e1: 3,
e2: 33,
},
f: {
f1: 4,
f2: 44,
},
}
};
执行getKeys(data, 44)
时,return将是[ 'b', 'd', 'e', 'f', 'f2' ]
,这是不正确的。
您需要做的是检查该值是否确实在当前节点下,只有在答案为是时才添加当前键。示例:
function getKeys(obj, val) {
if (!obj || typeof obj !== 'object')
return;
for (let [k, v] of Object.entries(obj)) {
if (v === val)
return [k];
let path = getKeys(v, val);
if (path)
return [k, ...path];
}
}
假设您只搜索 string
键,我们可以使用递归和回溯来检查键的子对象是否具有指定值。
如果有,则在我们的最终搜索字符串中添加父键。
为此,我使用 Object.entries()
遍历每对 [key, value]
并使用 Array.prototype.reduce()
累积结果:
var data = {
key1: 'str1',
key2: {
key3: 'str3',
key4: 'str4',
key5: {
key6: 'str6',
key7: 'str7',
key8: 'str8',
},
}
}
function getKeys(data, key, acc){
return Object.entries(data).reduce((acc, ele, idx) => {
if(ele.includes(key) && typeof ele[1] === "string"){
acc.push(ele[0]);
}
if(typeof ele[1] === "object" && !Array.isArray(ele[1]) && !(ele[1] instanceof Date)){
let old = acc.slice();
getKeys(ele[1], key, acc);
if(old.length !== acc.length){
acc.unshift(ele[0]);
}
}
return acc;
}, acc).join(" ");
}
console.log(getKeys(data, 'str1', []));
console.log(getKeys(data, 'str3', []));
console.log(getKeys(data, 'str6', []));