Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何通过知道LINQ中的子parentId来构建根元素的路径?_C#_Linq - Fatal编程技术网

C# 如何通过知道LINQ中的子parentId来构建根元素的路径?

C# 如何通过知道LINQ中的子parentId来构建根元素的路径?,c#,linq,C#,Linq,我有列表像 ID ParentID 1 0 2 7 3 1 4 5 5 1 6 2 7 1 8 6 9 0 10 9 我需要得到根的完整路径 0 __ 1__ 7__ 2__ 6__ 8 如果我们知道86 我的意思是我需要从父元素到根元素并构建层次结构 (到目前为止,我已经试过了。) 在linq中实现这一点最简单的方法是什么?这个问题不太适合linq,尽管您可以编写一个扩展方法来执行搜索并返回一个表示返回根目录的路由的IEnumerable。考虑到无限

我有
列表

ID  ParentID
1   0
2   7
3   1
4   5
5   1
6   2
7   1
8   6
9   0
10  9
我需要得到根的完整路径

0 __ 1__ 7__ 2__ 6__ 8
如果我们知道
86

我的意思是我需要从父元素到根元素并构建层次结构

(到目前为止,我已经试过了。)


在linq中实现这一点最简单的方法是什么?

这个问题不太适合linq,尽管您可以编写一个扩展方法来执行搜索并返回一个表示返回根目录的路由的
IEnumerable
。考虑到无限循环和路由可能无法完成,通过图形跟踪进度可能是一个好主意,以确保特定的
Id
不会被多次访问

public static class MyClassEx
{
    public static IEnumerable<MyClass> FindSourcePath(
        this MyClass startItem, 
        IList<MyClass> items)
    { 
        return startItem.FindSourcePath(items.ToDictionary(x => x.Id));
    }
    public static IEnumerable<MyClass> FindSourcePath(
        this MyClass startItem, 
        IDictionary<int, MyClass> itemDic)
    {
        var curr = startItem;
        var visited = new HashSet<int>();
        while (visited.Add(curr.Id))
        {
            yield return curr;
            if (curr.ParentId == 0)
            {
                yield break;
            }
            if (!itemDic.TryGetValue(curr.ParentId, out curr))
            {
                throw new Exception("invalid parent ref");
            }
        }
        throw new Exception("loop detected");
    }
}
公共静态类MyClassEx
{
公共静态IEnumerable FindSourcePath(
这是我班的明星,
IList项目)
{ 
返回startItem.FindSourcePath(items.ToDictionary(x=>x.Id));
}
公共静态IEnumerable FindSourcePath(
这是我班的明星,
词典条目(DIC)
{
var curr=星型;
var=newhashset();
while(访问添加(当前Id))
{
收益率回报率;
如果(curr.ParentId==0)
{
屈服断裂;
}
如果(!itemDic.TryGetValue(curr.ParentId,out curr))
{
抛出新异常(“无效父引用”);
}
}
抛出新异常(“检测到循环”);
}
}
并使用它:

List<MyClass> allItems = //...
var someItem = allItems[7];
IEnumerable<MyClass> hopsToRoot = someItem.FindSourcePath(allItems);
列出所有项目=/。。。
var someItem=allItems[7];
IEnumerable hopsToRoot=someItem.FindSourcePath(allItems);
产生(在你的例子中)序列

------------- | MyClass | ------------- Id | ParentId ============= 8 | 6 6 | 2 2 | 7 7 | 1 1 | 0 ------------- |我的班级| ------------- Id | ParentId ============= 8 | 6 6 | 2 2 | 7 7 | 1 1 | 0
这个问题不适合LINQ,尽管您可以编写一个扩展方法来执行搜索并返回一个表示返回根目录的路由的
IEnumerable
。考虑到无限循环和路由可能无法完成,通过图形跟踪进度可能是一个好主意,以确保特定的
Id
不会被多次访问

public static class MyClassEx
{
    public static IEnumerable<MyClass> FindSourcePath(
        this MyClass startItem, 
        IList<MyClass> items)
    { 
        return startItem.FindSourcePath(items.ToDictionary(x => x.Id));
    }
    public static IEnumerable<MyClass> FindSourcePath(
        this MyClass startItem, 
        IDictionary<int, MyClass> itemDic)
    {
        var curr = startItem;
        var visited = new HashSet<int>();
        while (visited.Add(curr.Id))
        {
            yield return curr;
            if (curr.ParentId == 0)
            {
                yield break;
            }
            if (!itemDic.TryGetValue(curr.ParentId, out curr))
            {
                throw new Exception("invalid parent ref");
            }
        }
        throw new Exception("loop detected");
    }
}
公共静态类MyClassEx
{
公共静态IEnumerable FindSourcePath(
这是我班的明星,
IList项目)
{ 
返回startItem.FindSourcePath(items.ToDictionary(x=>x.Id));
}
公共静态IEnumerable FindSourcePath(
这是我班的明星,
词典条目(DIC)
{
var curr=星型;
var=newhashset();
while(访问添加(当前Id))
{
收益率回报率;
如果(curr.ParentId==0)
{
屈服断裂;
}
如果(!itemDic.TryGetValue(curr.ParentId,out curr))
{
抛出新异常(“无效父引用”);
}
}
抛出新异常(“检测到循环”);
}
}
并使用它:

List<MyClass> allItems = //...
var someItem = allItems[7];
IEnumerable<MyClass> hopsToRoot = someItem.FindSourcePath(allItems);
列出所有项目=/。。。
var someItem=allItems[7];
IEnumerable hopsToRoot=someItem.FindSourcePath(allItems);
产生(在你的例子中)序列

------------- | MyClass | ------------- Id | ParentId ============= 8 | 6 6 | 2 2 | 7 7 | 1 1 | 0 ------------- |我的班级| ------------- Id | ParentId ============= 8 | 6 6 | 2 2 | 7 7 | 1 1 | 0
我觉得这需要某种形式的递归,而不是linq@JohnB我同意。我认为理论上这可能是错误的,因为时间已经晚了,您可以将其放入一个循环中,并继续对父id进行查询,直到得到结果中包含parentid的对象为止set@SomeStudent-我觉得这需要某种形式的递归,而不是linq@JohnB我同意。我认为理论上这可能是错误的,因为时间已经晚了,您可以将其放入一个循环中,并继续对父id进行查询,直到得到结果中包含parentid的对象为止set@SomeStudent-+1使用收益率,在浏览SO时学到了一些新东西。因此,如果我理解了文档,收益率将把当前元素添加到哈希集,然后在下一次循环迭代中,它应该从if语句开始?或者,yield关键字是否允许循环继续执行,即使在它达到返回值之后?@SomeStudent在评论的上下文中,很难澄清您的问题的一些细节。我建议你读一读(这篇文章看起来很直截了当),如果你不顺利的话,可以问一个问题。
IEnumerable/IEnumerator
yield
语句的神奇之处无法在此介绍(但非常值得一看)。+1对于使用yield,在浏览过程中学到了一些新东西。因此,如果我理解了文档,收益率将把当前元素添加到哈希集,然后在下一次循环迭代中,它应该从if语句开始?或者,yield关键字是否允许循环继续执行,即使在它达到返回值之后?@SomeStudent在评论的上下文中,很难澄清您的问题的一些细节。我建议你读一读(这篇文章看起来很直截了当),如果你不顺利的话,可以问一个问题。
IEnumerable/IEnumerator
yield
语句的魔力在这里无法涵盖(但非常值得研究)。