在IEnumerable集合中查找所有依赖子项的最佳方法是什么

时间:2010-07-17 17:19:04

标签: c# linq collections ienumerable

我有一个包含2个表的数据库:

  1. 产品
  2. ItemDependencies
  3. 项目具有ID

    的密钥

    ItemDependencies 有两列: ItemId DependsOnItemId

    我将其转换为集合:

     IEnumerable<Item> items = GetItems();
    

    每个都有一个:依赖关系属性

    List<Item>
    

    所以我想将初始项目列表过滤到:

    1. 给定一个项目,我想要一个该项目的列表以及递归依赖此项目的所有项目。

    2. 给定一个项目,我想要一个该项目的列表以及它所依赖的所有其他项目(也是递归的)。

    3. 在C#,LINQ或其他任何可以解决这个问题的方法中,最好的方法是什么。

2 个答案:

答案 0 :(得分:5)

要获取元素的所有依赖项列表,可以使用以下递归函数:

IEnumerable<Item> GetAllDependencies(Item i)
{
    IEnumerable<Item> a = new Item[] { i };
    IEnumerable<Item> b = i.Dependencies
                           .SelectMany(d => GetAllDependencies(d))
                           .Distinct();
    return a.Concat(b);
}

此方法假定依赖关系链中没有循环(如果存在循环,它将递归调用自身,直到它抛出StackOverflowException)。

为了反过来,我建议构建一个新的数据结构来保存反向依赖,然后重用相同的技术。

答案 1 :(得分:0)

这是获取所有依赖项的一种方法。

public IEnumerable<Item> GetAllDependencies(Item search)
{
    return PrivateGetAllDependencies(search, new HashSet<Item>());
}

private IEnumerable<Item> PrivateGetAllDependencies(Item search, HashSet<Item> visited)
{
    if (!visited.Contains(search))
    {
        visited.Add(search);
        foreach (Item child in search.Dependencies)
        {
            PrivateGetAllDependencies(child, visited);
        }
    }
    return visited;
}

这是获取所有参考文献的一种方法。

public IEnumerable<Item> GetAllBackReferences(Item search)
{
    return PrivateGetAllBackReferences(search, search, new HashSet<Item>(), new HashSet<Item>());
}

private IEnumerable<Item> PrivateGetAllBackReferences(Item search, Item target, HashSet<Item> visited, HashSet<Item> matched)
{
    if (!visited.Contains(search))
    {
        visited.Add(search);
        if (search == target)
        {
            matched.Add(search);
        }
        foreach (Item child in search.Dependencies)
        {
            PrivateGetAllBackReferences(child, target, visited, matched);
            if (child == target)
            {
                if (!matched.Contains(search))
                {
                    matched.Add(search);
                }
            }
        }
    }
    return matched;
}

两种算法都应该处理参考图中的循环。