Linq查询拼图

时间:2010-02-18 09:32:10

标签: c# linq

如果我有一个具有父子关系的对象,Id和ParentId表示记录的唯一ID和记录的父ID。

我需要一个查询对象列表的查询,并返回每个项目关系根目录的路径(即Path =(AllTheParentNames)\ Name)。

对此有任何帮助将不胜感激。

为MyObject

int Id
诠释?的ParentId
字符串名称
字符串路径

3 个答案:

答案 0 :(得分:4)

我相信这会给你预期的结果

        Func<int?, string> GetParents = null;

        List<URClass> lstRoot = new List<URClass>();
        lstRoot.Add(new URClass() { Id = 1, Name = "a", ParentId = null, Path = "1" });
        lstRoot.Add(new URClass() { Id = 2, Name = "b", ParentId = 1, Path = "1" });
        lstRoot.Add(new URClass() { Id = 3, Name = "c", ParentId = 2, Path = "1" });
        lstRoot.Add(new URClass() { Id = 4, Name = "d", ParentId = 3, Path = "1" });
        lstRoot.Add(new URClass() { Id = 5, Name = "e", ParentId = 4, Path = "1" });

        GetParents = i =>
        {
            var str = string.Empty;
            var outt = lstRoot.Where(x => x.Id == i).Select(x=>new {x.Name,x.ParentId });

            foreach (var lst in outt)
            {
                str += lst.Name;
                if (lst.ParentId != null)
                {
                      var outts = GetParents(lst.ParentId);
                      str += "," + outts;
                }                    
            }
            return str;

        };          

        var ks = from p in lstRoot
                 join q in lstRoot on p.Id equals q.ParentId
                 select new { q.Id, parentName = p.Name, parentid=p.Id, gpid=p.ParentId };


        List<string> RelationShip = new List<string>();

        foreach (var lst in ks)
        {
            var str = lst.parentName;
            if (lst.gpid != null)
            {
                 var prnt = GetParents(lst.gpid);
                 if (prnt != null)
                    str += "," + prnt;                   
            }
            str += "/" + lst.Id;
            RelationShip.Add(str); 
        }


        foreach (var ret in RelationShip)
            Console.WriteLine(ret);

输出将是

  

A / 2

     

B,A / 3

     

C,B,A / 4

     

d,C,B,A / 5

答案 1 :(得分:2)

首先,假设您有一个节点。您希望获得根路径。

让我们将根路径表示为一系列节点。

我们可以构建一个写一个方法,该方法接受一个项和一个标识下一个项的函数,并返回序列。

public static IEnumerable<T> Path(T item, Func<T, T> nextItem) where T : class
{
    T current = item;
    while(current != null)
    {
        yield return current;
        current = nextItem(current);
    }
}

现在,您可以在对象列表中编写查询。

List<Node> nodes = whatever;
var paths = from node in nodes 
            select Path(node, n=>GetNodeById(n.Parent));

现在你有了一系列节点序列。

假设您需要一系列字符串序列:

var namePaths = 
    from node in nodes 
    select (from pathElement in Path(node, n=>GetNodeById(n.Parent)) 
            select pathElement.Name);

等等。

有意义吗?

答案 2 :(得分:1)

这是预期的结果吗?

class A
{
    public int Id;
    public int? ParentId;
    public string Name;


    public static Func<T1, T2> Fix<T1, T2>(Func<Func<T1, T2>, Func<T1, T2>> f)
    {
        return f(x => Fix(f)(x));
    }

    public static string[] GetPaths(A[] array)
    {
        return array.Select(
            Fix<A, string>(self => x => x.ParentId != null ? self(array.First(a => a.Id == x.ParentId.Value)) + "\\" + x.Name : x.Name)
            ).ToArray();
    }
}

没有递归就不可能在单个查询中生成(数组上的foreach(Aggregate)可能对模拟递归有好处,但它很愚蠢)

修复 - 是Fixed point combinator