C#LINQ从列表中选择层次结构,其中root具有特定的属性值

时间:2015-05-13 20:22:04

标签: c# linq

我有一个具有以下属性的类:

  • int ID
  • INT? PARENTID
  • BOOL? NeedsShowing

我有一个这些对象的列表,该列表代表多个层次结构:ID是键值,而ParentID充当外键。 NeedsShowing仅在每个层次结构的根级别填充,这意味着它仅在ParentID == null时出现。

我需要完成的事情 - 最好是使用最简单的LINQ - 只选择列表中的那些层次结构,其中NeedsShowing == true(基本上应用过滤器)。

我在列表中有大约50,000个对象,代表大约13,000个层次结构。

代码

Public Class FileHierarchy
{
  int ID { get; set; }
  int? ParentID { get; set; }
  bool? NeedsShowing { get; set; }
}

带有值的FileHierarchy类列表:

ID     ParentID       NeedsShowing
----------------------------------
1      null           true
2      1              null
3      1              null
4      2              null
5      null           false
6      5              null
7      6              null
8      null           true
9      8              null

这意味着我有三个层次结构,根节点ID为1,5,8(其中parent ID == null)。我只想获取具有根ID 1和8的层次结构中的所有节点,因为根ID 5具有NeedsShowing == false

2 个答案:

答案 0 :(得分:1)

试试这个

List<FileHierarchy> mylist = GetList();
var selected = mylist.Where(s => s.NeedsShowing.HasValue && s.NeedsShowing.Value);
var children = mylist.Where(c => c.ParentID.HasValue && selected.Select(s => s.ID).Contains(c.ParentID.Value));
var unselected = mylist.Except(selected);
while (children.Any())
{
    unselected = unselected.Except(children);
    var childChild = unselected.Where(c => c.ParentID.HasValue && children.Select(s => s.ID).Contains(c.ParentID.Value));
    selected = selected.Union(children);
    children = childChild;
}

答案 1 :(得分:0)

我认为这更具可读性和可调性性,如果您愿意,可以调整结果。也许更快(避难所直接比较)。除了@ Zrethreal的答案之外,除了递归或超迭代之外,真的没办法做到这一点。我更喜欢递归。

    private static void Main(string[] args)
    {
        var files = GetFiles();
        var searchableFiles = files.Except(files.Where(f1 => f1.NeedsShowing ?? false && f1.ParentID == null)).ToList()
        var whereNeedShowing = (from f in files
                                where f.NeedsShowing ?? false
                                select new {Root = f, Descendants = FindDescendants(f.ID, searchableFiles) }).ToList();
        Debug.Assert(whereNeedShowing.Count == 2);
    }

    static List<FileHierarchy> FindDescendants(int? parentId, IEnumerable<FileHierarchy> files)
    {
        var children = files.Where(f => f.ParentID == parentId).ToList();
        foreach(var child in children.ToList())
        {
            var newChildren = FindDescendants(child.ID, files.Except(children));
            children.AddRange(newChildren);
        }
        return children;
    }

    static List<FileHierarchy> GetFiles()
    {
        var result = new List<FileHierarchy>();
        for (int i = 1; i <= 9; i++)
        {
            var file = new FileHierarchy()
            {
                ID = i, 
                ParentID = i == 1 || i == 5 || i == 8 ? (int?) null : i - 1, 
                NeedsShowing = i == 1 || i == 8 ? true : (i == 5 ? false : (bool?) null)
            };
            result.Add(file);
            if (i == 3)
            {
                file.ParentID = 1;
            }
            else if (i == 4)
            {
                file.ParentID = 2;
            }
        }
        return result;
    }
}

public class FileHierarchy
{
    public int ID { get; set; }
    public int? ParentID { get; set; }
    public bool? NeedsShowing { get; set; }
}