LINQ:如何将嵌套的分层对象转换为展平对象

时间:2009-12-21 05:42:54

标签: linq

如何使用LINQ将嵌套的分层对象转换为展平对象?我知道我们可以轻松使用foreach循环来实现这一点。但我想知道是否有办法在LINQ中编写它。

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

数据:

ID   : 1

Name : Jack

Children

2 | Rose 

3 | Paul

我想将此数据转换为扁平格式,如下所示。

1 | Jack 

2 | Rose 

3 | Paul

我们怎么能用Linq做到这一点?

2 个答案:

答案 0 :(得分:17)

如果你想让它在任意深度的树上变平,我建议如下:

public IEnumerable<Person> GetFamily(Person parent)
{
    yield return parent;
    foreach (Person child in parent.Children) // check null if you must
        foreach (Person relative in GetFamily(child))
            yield return relative;
}

使用LINQ没有任何好方法可以缩短它,因为匿名lambdas不能在不实现Y的情况下递归调用自己。你可以“减少”上面的方法

return parent.Children.SelectMany(p => GetFamily(p))
                      .Concat(new Person[] { parent });

或者

yield return parent;
    foreach (Person relative in parent.Children.SelectMany(GetFamily))
        yield return relative;

但这对我来说似乎没什么必要。

答案 1 :(得分:9)

这是一个很好的,通用的和可重用的扩展方法:

static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> descendBy)
{
    if (!source.IsNullOrEmpty())
    {
        foreach (T value in source)
        {
            yield return value;

            if (!descendBy(value).IsNullOrEmpty())
            {
                foreach (T child in descendBy(value).Descendants<T>(descendBy))
                {
                    yield return child;
                }
            }
        }
    }
}

在上面的例子中,使用如下:

var allChildren = parent.Children.Descendants(p => p.Children);

一个小问题是,它不包括列表中的原始父级,您需要这样做。