如何解决尝试根据嵌套对象中的给定值获取精确键 - Javascript使用递归
let menu = {
vegetarian: {
vegStarter: {
plainPizza: 100,cheesePizza: 200,onionPizza: 200
},},nonvegetarian: {
nonVegStarter: {
meatloversPizza: 160,chickenPizza: 200,chilliMeatPizza: 200
},nonVegMainCourse: {
seafoodPizza: 300,spinachEggPizza: 200,eggPizza: 250
}
}
};
我需要收集所有具有相同值的键,我必须使用递归。我的值是 200。我用 find() 和 filter() 方法尝试了代码,但没有得到想要的结果。下面是带有输出的代码:
function searchUsingPriceFromMainMenu(mainObject) {
let arrOfKeys = [];
Object.values(mainObject).forEach(val => {
if (val === 200 && typeof val !== "object") {
arrOfKeys = Object.keys(mainObject).filter(key => mainObject[key] === val);
document.write(arrOfKeys + "<br>")
} else {
if (typeof val === "object") {
searchUsingPriceFromMainMenu(val,arrOfKeys)
}
}
});
}
searchUsingPriceFromMainMenu(menu);
使用 filter() 方法:
cheesePizza,onionPizza
cheesePizza,onionPizza
chickenPizza,chilliMeatPizza
chickenPizza,chilliMeatPizza
spinachEggPizza
使用 find() 方法:只是使用了 find 而不是 filter。代码和上面一样。
cheesePizza
cheesePizza
chickenPizza
chickenPizza
spinachEggPizza
但我想要这样的结果:
cheesePizza
onionPizza
chickenPizza
chilliMeatPizza
spinachEggPizza
那么,我是不是遗漏了什么,还是有其他方法可以得到相同的结果?请帮忙。
解决方法
希望它会有所帮助 =)
const menu = {
vegetarian: {
vegStarter: {
plainPizza: 100,cheesePizza: 200,onionPizza: 200
},},nonVegetarian: {
nonVegStarter: {
meatLoversPizza: 160,chickenPizza: 200,chilliMeatPizza: 200
},nonVegMainCourse: {
seafoodPizza: 300,spinachEggPizza: 200,eggPizza: 250
}
}
};
const search = (obj,checkedValue) => {
const result = Object.entries(obj).flatMap(([key,value]) => {
if (typeof value === 'object') {
return search(value,checkedValue);
}
if (value === checkedValue) {
return key;
}
return [];
});
return result;
};
const searched = search(menu,200);
console.log(searched);
你可以抓取你的对象的条目,对于每个条目,检查它是否是一个对象。如果是,您可以调用递归函数来处理子对象。您可以将 this 的结果连接到结果数组 res
,该数组在您的函数结束时返回。否则,如果它不是对象,则可以检查pizza 值是否等于200
(即:val),如果是,则将其压入结果。
const menu = {vegetarian: { vegStarter: { plainPizza: 100,onionPizza: 200 },nonVegetarian: { nonVegStarter: { meatLoversPizza: 160,chilliMeatPizza: 200 },nonVegMainCourse: { seafoodPizza: 300,eggPizza: 250 }}};
const getPizzasByValue = (menu,val) => {
let res = [];
Object.entries(menu).forEach(([pizza,pizzaVal]) => {
if(Object(pizzaVal) === pizzaVal) { // check if value if object
res = res.concat(getPizzasByValue(pizzaVal,val));
} else if(pizzaVal === val) { // if value is not object,check if it matches the value
res.push(pizza);
}
});
return res;
}
console.log(getPizzasByValue(menu,200));
使用递归。
const menu = {vegetarian: { vegStarter: { plainPizza: 100,eggPizza: 250 }}};
function recurse(menuObj,val,arr) {
for (let key in menuObj) {
if (typeof menuObj[key] === "object") {
recurse(menuObj[key],arr);
} else if (menuObj[key] === val){
arr.push(key)
}
}
return arr;
}
console.log(recurse(menu,200,[]))
我们可以编写一个通用函数来根据谓词过滤输入对象的嵌套条目,然后在其上编写我们的菜单函数。这是一种实现:
const filterEntries = (pred) => (obj) =>
Object .entries (obj) .flatMap ((entry) => [
... (pred (entry) ? [entry] : []),... (typeof entry [1] == 'object' ? filterEntries (pred) (entry [1]) : [])
])
const matchingPrice = (price,menu) =>
filterEntries (([k,v]) => v === price) (menu)
.map (([k,v]) => k)
const menu = {vegetarian: {vegStarter: {plainPizza: 100,onionPizza: 200}},nonVegetarian: {nonVegStarter: {meatLoversPizza: 160,chilliMeatPizza: 200},nonVegMainCourse: {seafoodPizza: 300,eggPizza: 250}}}
console .log (matchingPrice (200,menu))
重点是JS对象可以被认为是键值对的集合。所以这个对象:
{
plainPizza: 100,onionPizza: 200
}
可以被认为包含这些键值对:
[
['plainPizza',100],['cheesePizza',200],['onionPizza',200]
}
还有这个:
{
nonVegStarter: {
meatLoversPizza: 160,chilliMeatPizza: 200
},nonVegMainCourse: {
seafoodPizza: 300,eggPizza: 250
}
}
由这两个键值对组成:
[
['nonVegStarter',{meatLoversPizza: 160,chilliMeatPizza: 200}],['nonVegMainCourse',{seafoodPizza: 300,eggPizza: 250}]
]
使用递归添加我们对象的所有嵌套子项,我们可以在我们的对象中找到所有此类键值对的列表。它可能看起来像这样:
[
["vegetarian",{vegStarter: {cheesePizza: 200,onionPizza: 200,plainPizza: 100}}],["vegStarter",{cheesePizza: 200,plainPizza: 100}],["plainPizza",["cheesePizza",["onionPizza",["nonVegetarian",{nonVegStarter: {meatLoversPizza: 160,eggPizza: 250}}],["nonVegStarter",["meatLoversPizza",160],["chickenPizza",["chilliMeatPizza",["nonVegMainCourse",eggPizza: 250}],["seafoodPizza",300],["spinachEggPizza",["eggPizza",250]
]
我们的 filterEntries
函数执行此操作并应用谓词函数(为每个值返回 true
或 false
)来查找对象中与某个条件匹配的所有条目。它获取我们对象的每个条目并创建一个新的条目数组。如果谓词匹配给定的条目,则包括该条目,然后,如果该条目的值是一个对象,我们递归调用 filterEntries
具有相同的谓词和该值,包括数组中的所有匹配结果。然后使用 flatMap
将每个条目的数组组合成一个数组。
然后我们在 matchingPrice
中使用它,创建一个函数来测试一个条目以查看该值是否与我们给定的价格匹配,并将其与我们的菜单对象一起传递给 filterEntries
。这将创建一个像这样的条目数组:
[
["cheesePizza",200]
]
最后的 map
调用将这些转换为
[
"cheesePizza","onionPizza","chickenPizza","chilliMeatPizza","spinachEggPizza"
]
将 filterEntries
稍微不同地编写是一个很好的论据,将过滤分层在一个单独的实用函数之上,该函数将所有条目生成为一个数组。这不会有太大的不同:
const allEntries = (obj) =>
Object .entries (obj) .flatMap ((entry) => [
entry,... (typeof entry [1] == 'object' ? allEntries (entry [1]) : [])
])
const filterEntries = (pred) => (obj) =>
allEntries (obj) .filter (pred)
这样做的好处是可以创建两个有用的实用函数,而不仅仅是一个。
,这是我对使用 JavaScript 生成器的问题的看法。首先,我们从一个函数开始,该函数生成树的所有叶子 t
,并且只产生那些与 price
输入匹配的叶子
function* matchingPrice (t,price)
{ for (const [k,v] of leafs(t))
if (v == price)
yield k
}
现在我们编写一个 leafs
函数,它对输入 t
进行简单的类型分析,在对象上递归,否则将输入 key
和 t
作为对 -
function* leafs (t,key)
{ switch (t?.constructor)
{ case Object:
for (const [k,v] of Object.entries(t))
yield* leafs(v,k)
break
default:
yield [key ?? null,t]
}
}
把它们放在一个可执行的片段中 -
function* matchingPrice (menu,v] of leafs(menu))
if (v == price)
yield k
}
function* leafs (t,t]
}
}
const menu =
{vegetarian: {vegStarter: {plainPizza: 100,eggPizza: 250}}}
console.log(Array.from(matchingPrice(menu,200)))
输出 -
[
"cheesePizza","spinachEggPizza"
]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。