使用LAMBDA表达式获取具有相同类型的对象的对象树的深度

时间:2014-01-23 12:41:18

标签: c# algorithm object lambda generic-list

我有这个对象:

public class dtHeader
{
    public dtHeader ParentHeader { get; set; }
    public string HeaderText { get; set; }
    public string DataField { get; set; }
    public bool Visible { get; set; }
    public int DisplayOrder { get; set; }
}

我想用lambda表达式计算,对象的深度,对象本身有多少层?

我看到this JavaScript post,但我正在努力将其转换为单行lambda语句。

让我们说对象就是这个new dtHeader(){ ParentHeader = null, HeaderText = "col1" }; 结果将是1

new dtHeader(){ ParentHeader = new dtHeader(){ ParentHeader = null, HeaderText = "col1" }, HeaderText = "col1" };结果为2

我希望用list<dtHeader>实现这一目标,因此其中一些深度为1,其他深度更深,并且需要最深的深度。

    _______ITEM_IN_LIST_OBJECT__
    ______1___2___3___4___5___6_
 D  1.  |_o_|_o_|_o_|_o_|_o_|_o_|
 E  2.  |_o_|___|_o_|___|_o_|_o_|
 P  3.  |___|___|_o_|___|_o_|___|
 T  4.  |___|___|___|___|_o_|___|
 H  5.  |___|___|___|___|_o_|___|

它必须无限(直到它允许对象在彼此内部堆积)深。

var HeaderLayerCount = lDtCol.Where(n => n.ParentHeader != null)
                             .Where(n => n.ParentHeader.ParentHeader != null)
                             .Where(n => n.ParentHeader.ParentHeader.ParentHeader != null);

修改: 我只想补充一点,如果你想在特定的深度级别上工作,例如深度为3的所有对象,你可以在类中使用这个额外的递归函数

public class dtCol
{
    public dtCol ParentHeader { get; set; }
    public string HeaderText { get; set; }
    public string DataField { get; set; }
    public bool Visible { get; set; }
    public int DisplayOrder { get; set; }
    public int Depth { get { return ParentHeader != null ? ParentHeader.Depth + 1 : 1; } }
    public int CurrentDepth { get; set; } //Set on initialisation
    public dtCol getParent(dtCol col, int getDepth) //Gets the parent on a specific level after the first base level (1) else returns the previous not null child
    {
        return (col.ParentHeader != null && col.ParentHeader.CurrentDepth == getDepth) ? col.ParentHeader : this.getParent(col.ParentHeader, getDepth);
    }
}

您可以像这样使用它:

var HeaderLayerCount = lDtCol.OrderByDescending(n => n.Depth).First().Depth;
for (int hlc = 1; hlc <= HeaderLayerCount; hlc++)
{
    var headerrow = new List<dtCol>();
    //This foreach adds the parent header if not null else adds the not null child
    lDtCol.ForEach(n =>
    {
        var h = n.getParent(n, hlc); //Get Parent, null is returned if parent does not exists
        headerrow.Add((h != null) ? h : n); //If parent is null, add base dtCol so that the headers can be merged upwards.
    });

    //Do what you need with your new single dimensional list of objects
}

4 个答案:

答案 0 :(得分:4)

为什么不在你的类上实现一个get getDepth()方法,它将达到最高的祖先,计算每个级别?

您的查询会更加简单。

我被弗洛德击败,对他不满

我有相同的实现:

 public int GetDepth()
        {
            if (ParentHeader == null)
            {
                return 1;
            }
            else return 1 + ParentHeader.GetDepth();
        }

答案 1 :(得分:2)

using System;
using System.Linq;

namespace ConsoleApplication3
{
    public class dtHeader
    {
        public dtHeader ParentHeader { get; set; }
        public string HeaderText { get; set; }
        public string DataField { get; set; }
        public bool Visible { get; set; }
        public int DisplayOrder { get; set; }
        public int Depth
        {
            get
            {
                // If header has parent, then this depth is parent.depth + 1
                if (ParentHeader != null)
                    return ParentHeader.Depth+1;
                else
                    return 1; // No parent, root is depth 1
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            dtHeader[] headers = { 
                                     new dtHeader { HeaderText = "dt1" },
                                     new dtHeader { HeaderText = "dt2" },
                                     new dtHeader { HeaderText = "dt3" },
                                     new dtHeader { HeaderText = "dt4" },
                                     new dtHeader { HeaderText = "dt5" }
                                 };

            headers[1].ParentHeader = headers[0];
            headers[2].ParentHeader = headers[1];
            headers[3].ParentHeader = headers[2];
            headers[4].ParentHeader = headers[3];

            var deepest = headers.OrderByDescending(item=>item.Depth).First();
            Console.WriteLine(deepest.Depth+ ", " + deepest.HeaderText);

            var runner = deepest;
            while (runner.ParentHeader != null)
                runner = runner.ParentHeader;

            Console.WriteLine("The deepest root header is:" + runner.HeaderText);
        }
    }
}

答案 2 :(得分:2)

这是一个lambda表达式,可以得到你想要的东西:

Func<dtHeader, int> getDepth = null;
getDepth = dth =>
{
    var depth = 1;
    if (dth.ParentHeader != null)
    {
        depth += getDepth(dth.ParentHeader);
    }
    return depth;
};

您必须将其分为两部分(分配null并指定正文)以使递归工作。

答案 3 :(得分:0)

我修改了Enigmativity的答案,使其正常工作:

Func<dtHeader, int, int> getDepth = null;
getDepth = (dth, depth) =>
{
    if (dth.ParentHeader != null)
    {
        depth = getDepth(dth.ParentHeader, ++depth);
    }

    return depth;
};

这样称呼:

int depth = getDepth(header, 0)