递归函数不会迭代到 foreach 中的下一个元素

问题描述 投票:0回答:2

在我看来,在 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);

您可以在这里找到重现示例:

示例重现链接

javascript typescript recursion
2个回答
0
投票

问题是你的

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;
}

0
投票

发电机

我认为生成器提供了一种自然的方式来表达搜索功能。我们可以看到生成器如何在继续

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)) // []
© www.soinside.com 2019 - 2024. All rights reserved.