LINQ获得所有heirerichal儿童

时间:2016-02-01 05:51:58

标签: c# linq

我一直在挖这个。

public class Person
{
   public string Name { get; set; }    
   public string Age { get; set; }    
   public List<Person> Children { get; set; }    
}

我想要一个LINQ查询来查找&#34;此集合中Age > 4的所有人&#34;。

注意:您必须遍历Person + Children集合的集合,因此每个子对象的Person集合将Children变为null {{1}} }。

3 个答案:

答案 0 :(得分:3)

首先,我无法理解为什么您的所有属性privateAge都不是int类型。所以我的班级看起来像这样:

public partial class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public List<Person> Childrens { get; set; }
}

注意partial字。这个单词将允许您将类逻辑放在单独的文件中,这在您在类中创建一些自定义逻辑时非常有用。

然后我只是在不同的文件中创建此方法:

public partial class Person
{
    public Person GetPersonWithChindren(int maxAge)
    {
        return new Person
        {
            Age = this.Age,
            Name = this.Name,
            Childrens = this.Childrens != null 
            ? this.Childrens
                .Where(x => x.Age < maxAge)
                .Select(x => x.GetPersonWithChindren(maxAge)) //this line do recursive magic
                .ToList() 
            : null
        };
    }
}

正如您可以看到此方法检查每个孩子的Age,如果Age正常,那么它会检查下一级别的层次结构,直到Childrensnull

所以你可以像这样使用它:

var person = new Person()
{
  //initialisation of your collection here
}

//result will contains only nodes where Person have age < 4 and Childs that have age < 4
var result = person.GetPersonWithChindren(4);

请注意,此解决方案可以正常使用 linqToEntities 。但是,如果您使用 LinqToSQL ,则此表达式会在每个Person实体上生成对DB的查询。因此,如果你有很多人和深层次,那么你需要花费大量的机器时间。在这种情况下,您应该使用 CTE 而不是LinQ查询来编写存储过程。

<强>更新

你甚至可以在Func<T>类的帮助下编写更通用的解决方案,如下所示:

public partial class Person
{
    public Person GetPersonWithChindren(Func<Person, bool> func)
    {
        return new Person
        {
            Age = this.Age,
            Name = this.Name,
            Childrens = this.Childrens != null
            ? this.Childrens
                .Where(x => func(x))
                .Select(x => x.GetPersonWithChindren(func))
                .ToList()
            : null
        };
    }
}

然后你可以像这样使用它:

var result = person.GetPersonWithChindren(x => x.Age < 4);

您现在可以随时更改您要使用功能的条件。

答案 1 :(得分:3)

创建访问者。在此示例中,通过实现帮助程序类:

public static class Helpers
public static IEnumerable<Person> GetDescendants(this Person person)
{
    foreach (var child in person.Children)
    {
        yield return child;
        foreach (var descendant in child.GetDescendants())
        {
           yield return descendant;
        }
    }
}

这是&#34;收益率回归很多的时代之一。会很有用。

答案 2 :(得分:1)

如果你确保自动创建.Children,那么这可行:

Func<Person, Func<Person, bool>, Person> clone = null;
clone = (p, f) => f(p) ? new Person()
{
    Name = p.Name,
    Age = p.Age,
    Children = p.Children.Select(c => clone(c, f)).Where(x => x != null).ToList(),
} : null;

var olderThan4 = clone(person, p => p.Age > 4);

是的,就是这样。实际上有三行。

如果您从这些数据开始:

var person = new Person()
{
    Name = "Fred", Age = 30,
    Children = new List<Person>()
    {
        new Person() { Name = "Bob", Age = 7, },
        new Person() { Name = "Sally", Age = 3, }
    },
};

...然后你得到这个结果:

result

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    private List<Person> _children = null;
    public List<Person> Children
    {
        get
        {
            if (_children == null)
            {
                _children = new List<Person>();
            }
            return _children;
        }
        set
        {
            _children = value;
        }
    }
}