在我看来,在 for 循环中永远不会到达 items 中第二项的代码。
如何修复此方法?
class Item {
items: Item[] = [];
constructor(public id: string){}
}
function getItembyIdRecursively(id: string, items: Item[]) : Item |undefined{
for(const item of items)
{
if(item.id === id)
{
return item;
}
else
{
return getItembyIdRecursively(id,item.items);
}
}
return undefined;
}
const item1 = new Item("1");
const item2 = new Item("2");
item1.items.push(new Item("1.2"));
const items = [item1, item2];
const foundItem = getItembyIdRecursively("2", items);
console.log(foundItem.id);
您可以在这里找到重现示例:
问题是你的
else
语句,你在所有情况下都会返回结果,即使它是 undefined
。基本上,由于第一个 Item
有子级,因此您将在其子级中返回搜索结果,并且由于 id 不匹配,因此您会得到 undefined
。
function getItembyIdRecursively(id: string, items: Item[]) : Item | undefined
{
for(const item of items)
{
if(item.id === id)
{
return item;
}
else
{
const elem = getItembyIdRecursively(id, item.items);
if(elem) {
return elem;
}
}
}
return undefined;
}
和这个一样。
function getItembyIdRecursively(id: string, items: Item[]) : Item | undefined
{
for(const item of items)
{
if(item.id === id) return item;
const elem = getItembyIdRecursively(id, item.items);
if(elem !== undefined) return elem;
}
return undefined;
}
发电机
我认为生成器提供了一种自然的方式来表达搜索功能。我们可以看到生成器如何在继续
if
之前不需要额外的 yield*
检查。另一个好处是消费者始终能得到价值保证
function getItem(id: string, items: Item[]): undefined | Item {
function* find(items: Item[]): Generator<Item> {
for (const item of items) {
if (item.id == id) yield item
yield* find(item.items) // unconditional
}
}
for (const match of find(items))
return match // unconditional
}
class Item {
items: Item[]
constructor(
public id: string,
items?: Item[],
) {
this.items = items ?? []
}
}
const example = [
new Item("A", [
new Item("B", [new Item("C"), new Item("D", [new Item("E")])]),
new Item("F"),
]),
]
console.log(getItem("D", example)) // Item: { id: "D", items: [ Item: { id: "E", items: [] } ] }
console.log(getItem("X", example)) // undefined
通用查找
我们可以将
getItem
定义为独立函数,独立于 find
类型 -,而不是将生成器嵌入到
Item
函数中
function* find<T>(
values: Iterable<T>,
matchFn: (value: T) => boolean,
recurFn?: (value: T) => Iterable<T>,
): Generator<T> {
for (const value of values) {
if (matchFn(value)) yield value
if (recurFn) yield* find(recurFn(value), matchFn, recurFn)
}
}
现在
find
可以在我们需要此功能的任何地方重复使用,例如 getItem
-
function getItem(id: string, items: Item[]): undefined | Item {
for (const match of find( // find..
items, // iterable
i => i.id == id, // match
i => i.items, // recur
))
return match // unconditional
}
console.log(getItem("D", example)) // Item: { id: "D", items: [ Item: { id: "E", items: [] } ] }
console.log(getItem("X", example)) // undefined
方便和控制:$0.99
发电机为我们提供了各种动力和灵活性。
getItem
仅返回第一个结果,这会立即终止生成器并停止扫描其他项目。通过一个微小的改变,我们可以编写 getItems
来返回 all 结果 -
function getItems(ids: string[], items: Item[]): Item[] {
return Array.from(find( // unconditional
items,
i => ids.includes(i.id),
i => i.items,
))
}
console.log(getItems(["E", "F"], example)) // [ Item: { id: "E" }, Item: { id: "F" } ]
console.log(getItems(["X"], example)) // []