我有一个id / parents列表,我正在迭代外部扩展。这个列表可以有大约11 000行,这就是为什么我需要删除一些元素,所以我只显示我需要的那些。
元素列表:
FlatData[] elements = new FlatData[]
{
new FlatData {Id = 3, ParentId = 1, Text = "A"},
new FlatData {Id = 4, ParentId = 1, Text = "D"},
new FlatData {Id = 5, ParentId = 2, Text = "E"},
new FlatData {Id = 7, ParentId = 2, Text = "G"},
new FlatData {Id = 8, ParentId = 4, Text = "H"},
new FlatData {Id = 9, ParentId = 8, Text = "H"},
new FlatData {Id = 10, ParentId = 8, Text = "I"},
new FlatData {Id = 11, Text = "I"},
};
虽然我正在迭代,但我想删除一些元素,以便它们不会被处理或显示,但我要删除的元素仍然存在于输出中!
这里的代码通过元素迭代:
int firstDepth = 0;
IEnumerable <DeepNodeData> nodes = elements.Where(x => x.Id >= 4).RecursiveJoin(element => element.Id,
element => element.ParentId,
(FlatData element, int index, int depth, IEnumerable<DeepNodeData> children) =>
{
int position;
if(depth == 0){
firstDepth++;
}
if(firstDepth > 0){
position= Array.FindIndex(elements, row => row.Id == index);
elements.Skip(position);
}
return new DeepNodeData()
{
Id = element.Id,
Index = index,
Text = element.Text,
};
});
我只知道作为根父母的起始位置(id = 4)。一旦我有了深度值,我只会知道要删除的元素的位置。我们的想法是只显示附加到id = 4的子项。这里是我应该在最后得到的元素,应该处理它以构建我的树视图:
FlatData[] elements = new FlatData[]
{
new FlatData {Id = 4, ParentId = 1, Text = "D" },
new FlatData {Id = 8, ParentId = 4, Text = "H" },
new FlatData {Id = 9, ParentId = 8, Text = "H" },
};
The Recusive Extension:
public static IEnumerable<TResult> RecursiveJoin<TSource, TKey, TResult>(this IEnumerable<TSource> source,
Func<TSource, TKey> parentKeySelector,
Func<TSource, TKey> childKeySelector,
Func<TSource, int, int, IEnumerable<TResult>, TResult> resultSelector)
{
return RecursiveJoin(source, parentKeySelector, childKeySelector,
resultSelector, Comparer<TKey>.Default);
}
public static IEnumerable<TResult> RecursiveJoin<TSource, TKey, TResult>(this IEnumerable<TSource> source,
Func<TSource, TKey> parentKeySelector,
Func<TSource, TKey> childKeySelector,
Func<TSource, int, int, IEnumerable<TResult>, TResult> resultSelector,
IComparer<TKey> comparer)
{
// prevent source being enumerated more than once per RecursiveJoin call
source = new LinkedList<TSource>(source);
// fast binary search lookup
SortedDictionary<TKey, TSource> parents = new SortedDictionary<TKey, TSource>(comparer);
SortedDictionary<TKey, LinkedList<TSource>> children
= new SortedDictionary<TKey, LinkedList<TSource>>(comparer);
foreach (TSource element in source)
{
parents[parentKeySelector(element)] = element;
LinkedList<TSource> list;
TKey childKey = childKeySelector(element);
if (!children.TryGetValue(childKey, out list))
{
children[childKey] = list = new LinkedList<TSource>();
}
list.AddLast(element);
}
// initialize to null otherwise compiler complains at single line assignment
Func<TSource, int, IEnumerable<TResult>> childSelector = null;
childSelector = (TSource parent, int depth) =>
{
LinkedList<TSource> innerChildren = null;
if (children.TryGetValue(parentKeySelector(parent), out innerChildren))
{
return innerChildren.Select((child, index)
=> resultSelector(child, index, depth , childSelector(child, depth + 1)));
}
return Enumerable.Empty<TResult>();
};
return source.Where(element => !parents.ContainsKey(childKeySelector(element)))
.Select((element, index) => resultSelector(element, index, 0 ,childSelector(element, 1)));
}