如何修复使用递归和数组时的错误?
2022-07-14
85
我正在尝试解决一个问题 - 在输入要搜索的值后需要返回一个数组。数组的深度理论上可以是无限的。因此,我递归地在任何深度级别中找到合适的元素并将它们添加到数组中,然后返回此数组。但是此代码无法按预期工作。我搞不清楚我到底做错了什么。
const newList = [
{
role: "role111",
title: "title1",
},
{
role: "role222",
title: "title2",
},
{
role: "role333",
title: "title3",
},
{
role: "role444",
title: "title4",
items: [{
role: "role555",
title: "title5",
}, {
role: "role666",
title: "title6",
}, {
role: "role777",
title: "title7",
items: [{
role: "role888",
title: "title888",
},{
role: "role8888",
title: "title8888",
},]
},]
},
{
role: "role999",
title: "title999",
},
];
const text = "role888";
const testFunction = (
list,
text,
emptyArray
) => {
let arrayForRender = emptyArray;
return list?.filter((item) => {
if (item.title.toLowerCase().includes(text.toLowerCase())) {
arrayForRender = [...arrayForRender, item];
return arrayForRender;
}
if (item.items && item.items?.length > 0) {
testFunction(item.items, text, arrayForRender);
}
});
};
console.log(testFunction(newList, text, []));
附注:非常抱歉,但我的问题最初表述错误,不再相关。但感谢所有提出建议的人,他们会告诉你如何正确使用递归!
2个回答
如果我理解了您更新后的要求,那么我们可以编写一个简单的通用深度过滤函数,该函数显示与谓词匹配的所有元素或具有与之匹配的(递归嵌套)后代的元素。
我们可以使用一个函数来配置它,该函数测试标题是否与查询字符串匹配。它可能看起来像这样:
const filterDeep = (pred) => (xs) =>
xs .filter (x => pred (x) || filterDeep (pred) (x .items || []) .length > 0)
const titleMatch = (query) => filterDeep (
({title}) => title .toLowerCase () .includes (query .toLowerCase ())
)
const newList = [{role: "role111", title: "title1"}, {role: "role222", title: "title2"}, {role: "role333", title: "title3"}, {role: "role444", title: "title4", items: [{role: "role555", title: "title5"}, {role: "role666", title: "title6"}, {role: "role777", title: "title7", items: [{role: "role888", title: "title888"}, {role: "role8888", title: "title8888"}]}]}, {role: "role999", title: "title999"}];
['title2', '888', 'itl'] .forEach (
query => console .log (`"${query}"`, ':', titleMatch (query) (newList) .map (x => x .title))
)
.as-console-wrapper {max-height: 100% !important; top: 0}
(请注意,结果是实际的原始节点,但这里我们只显示它们的标题。)
我认为这是简单的代码,并且
filterDeep
很可能在其他地方可用。
更新
很明显,我没有得到要求。如果我现在是正确的,并且您想要与谓词匹配的任何节点的完整对象层次结构,那么这个版本应该可以做到,它只是对
filterDeep
进行了不同的实现:
const filterDeep = (pred) => (xs) =>
xs .flatMap (({items = [], kids = filterDeep (pred) (items), ...rest}) =>
pred (rest) || kids.length
? [{...rest, ...(kids.length ? {items: kids} : {})}]
: []
)
const titleMatch = (query) => filterDeep (
({title}) => title .toLowerCase () .includes (query .toLowerCase ())
)
const newList = [{role: "role111", title: "title1"}, {role: "role222", title: "title2"}, {role: "role333", title: "title3"}, {role: "role444", title: "title4", items: [{role: "role555", title: "title5"}, {role: "role666", title: "title6"}, {role: "role777", title: "title7", items: [{role: "role888", title: "title888"}, {role: "role8888", title: "title8888"}]}]}, {role: "role999", title: "title999"}];
['title2', '888', 'itl'] .forEach (
query => console .log (`"${query}"`, ':', titleMatch (query) (newList))
)
.as-console-wrapper {max-height: 100% !important; top: 0}
我们在这里使用
flatMap
作为一次性
filter
和
map
的一种方式。如果项目不匹配,我们将返回一个空数组;如果匹配,那么我们将返回一个仅包含其转换值的数组。
Scott Sauyet
2022-07-14
我认为 filter 方法在这里不起作用,而是尝试使用 forEach 方法循环遍历数组并将找到的项目推送到
arrayForRender
。我还注意到在您的代码中,您的搜索文本是一个角色,但您的条件是查看标题。
const testFunction = (
list,
text,
arrayForRender
) => {
list.forEach((item) => {
if (item.items && item.items?.length > 0) {
testFunction(item.items, text, arrayForRender);
}
if (item.role.toLowerCase().includes(text.toLowerCase())) {
arrayForRender.push(item);
//arrayForRender.push({'role':item.role, 'title':item.title})
}
});
return(arrayForRender)
};
console.log("search results:",testFunction(newList, text,[]));
根据您下面的评论,以下代码仅返回顶级节点(如果它与搜索匹配或其任何子节点与搜索匹配):
const testFunction = (
list,
text
) => {
return list?.filter((item) => {
if (item.items && item.items?.length > 0) {
return testFunction(item.items, text);
}
return item.role.toLowerCase().includes(text.toLowerCase());
});
};
console.log("search results:",testFunction(newList, text));
Woodsy
2022-07-14