我有以下层次结构,我需要将其展平并选择所有Id
。我尝试使用SelectMany()
这样的.SelectMany(node => node.Children).Select(node => node.Id)
。这将产生 3,5,6 的列表。是否有可能使用Linq获得完整列表 1,2,3,4,5,6,7 ?
答案 0 :(得分:2)
您可以使用以下扩展方法来展平层次结构(请参阅下面的答案更新中的替代展平算法):
public static IEnumerable<T> Flatten<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector)
{
foreach (var item in source)
{
yield return item;
var children = childrenSelector(item);
if (children == null)
continue;
foreach (var child in children.Flatten(childrenSelector))
yield return child;
}
}
我接受子选择器并递归生成子项。然后投影很简单:
var result = nodes.Flatten(n => n.Children).Select(n => n.Id);
假设您有以下Node类:
public class Node
{
public Node(int id, params Node[] children)
{
Id = id;
if (children.Any())
Children = new List<Node>(children);
}
public int Id { get; set; }
public List<Node> Children { get; set; }
}
然后使用您的样本层次结构:
List<Node> nodes = new List<Node> {
new Node(1),
new Node(2, new Node(3)),
new Node(4, new Node(5),
new Node(6, new Node(7)))
};
输出将是:
1, 2, 3, 4, 5, 6, 7
UPDATE :您可以在不使用递归的情况下展平层次结构(以获得更好的性能):
public static IEnumerable<T> Flatten<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector)
{
Queue<T> queue = new Queue<T>();
foreach (var item in source)
queue.Enqueue(item);
while (queue.Any())
{
T item = queue.Dequeue();
yield return item;
var children = childrenSelector(item);
if (children == null)
continue;
foreach (var child in children)
queue.Enqueue(child);
}
}
答案 1 :(得分:0)
易。
Func<IEnumerable<Node>, IEnumerable<int>> flatten = null;
flatten = ns =>
{
return ns.Select(n => n.Id)
.Concat(ns.SelectMany(n => flatten(n.Children)));
};
答案 2 :(得分:0)
您可以使用扩展方法展平层次结构:
public static IEnumerable<Node> Flatten(this IEnumerable<Node> source)
{
if(source == null)
throw new ArgumentNullException("source");
return FlattenIterator(source);
}
private static IEnumerable<Node> FlattenIterator(IEnumerable<Node> source)
{
foreach(var node in source)
{
yield return node;
foreach(var child in node.Children.Flatten())
{
yield return child;
}
}
}
然后你可以选择这样的ID:
var ids = source.Flatten().Select(n => n.Id);