LINQ:如何将嵌套的分层对象转换为扁平对象
问题描述:
如何使用LINQ将嵌套的分层对象转换为扁平化对象?我知道我们可以很容易地使用foreach循环来实现这一点。但我想知道是否有方法在LINQ中编写它。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做到这一点?
答
如果你想让它变平的人任意深树,我建议如下:
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缩短这个没有什么好的办法,因为匿名的lambda不能打电话自己没有递归执行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;
但这对我来说似乎没有必要。
答
这是一个很好的,通用的,可重用的扩展方法:
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);
一个次要尼特的是,它不包括原父母在列表中,你需要这样做。
当然lambda可以自称。这是Fibonacci使用递归lambda:'Func fib = null; fib = i => i
2012-08-27 12:36:02
我说“匿名* lambda不能调用自己”,这就是为什么他不能写一个表达式来返回他想要的值 - - 他需要声明一个命名的函数来递归。 – mquander 2012-08-28 03:16:10
因此,通过在变量中放置匿名内容,它不再是匿名的?例如。 'var a = new {X = 5};'?我仍然会调用'a'引用一个匿名类型。 Microsoft无条件地表示[“lambda表达式是匿名函数”](http://msdn.microsoft.com/zh-cn/library/bb397687.aspx),并查看[匿名方法]的第二个示例(http: //msdn.microsoft.com/en-us/library/0yw3tz5k.aspx)。几乎所有的匿名都必须放在某种指定的变量或参数中;否则它们不能被代码使用。这并不意味着他们不是匿名的。 – 2012-08-28 08:07:43