我有一个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 = 3, Text = "I"},
new FlatData {Id = 11, Text = "I"},
};
虽然我正在迭代,但我想删除一些元素,以便它们不会被处理或显示,但我要删除的元素仍然存在于输出中!
这里的代码通过元素迭代:
int firstDepth = 0;
IEnumerable <DeepNodeData> nodes = elements.Where(x => x.Id >= 5).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);
// or much better, exit the program with something like break ?;
}
return new DeepNodeData()
{
Id = element.Id,
Index = index,
Text = element.Text,
Children = children
};
});
我只知道作为根父母的起始位置(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" },
};
最终输出应为:
[
{
"id": 4,
"index": 1,
"depth": 0,
"parentId": 0,
"text": "D",
"children": [
{
"id": 8,
"index": 1,
"depth": 1,
"parentId": 0,
"text": "H",
"children": [
{
"id": 9,
"index": 1,
"depth": 2,
"parentId": 0,
"text": "H",
"children": []
}
]
}
]
}
]
递归扩展程序:
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)));
}
答案 0 :(得分:3)
而不是
.Where(x => x.Id >= 5)
试
.Where(x => x.Id >= 5 && x.Id != 11)
如果您不知道ID但知道索引(列表中的偏移量),则可以使用alternative overload of Where
获取索引,该索引将where索引作为第二个参数提供给where。
.Where
(
(row, index) => row.Id > 5 //Filter on data
&& index != 11 //Filter on row index
)
或者您可以简单地执行此操作(效率稍低):
.Where(x => x.Id >= 5 && x.Id != elements[11].Id)
如果(基于您的编辑)您正在寻找一个包含父ID的子孙列表,您可以使用这样的方法来搜索树:
public static class ExtensionMethods
{
public static IEnumerable<FlatData> GetDescendents(this IEnumerable<FlatData> This, int rootId)
{
var rootItem = This.Single( x => x.Id == rootId );
var queue = new Queue<FlatData>( new [] { rootItem } );
while (queue.Count > 0)
{
var item = queue.Dequeue();
yield return item;
foreach (var child in This.Where( x => x.ParentId == item.Id ))
{
queue.Enqueue(child);
}
}
}
}
然后使用
var filtered = elements.GetDescendents(4);
如果您需要限制级别,您可以尝试这种方法,效率较低,但会明确每个孩子在哪个级别以及何时停止搜索:
public static IEnumerable<FlatData> GetDescendents(this IEnumerable<FlatData> This, int rootId, int maxDepth)
{
var results = Enumerable.Range(0, maxDepth+1 ).Select( i => new List<FlatData>() ).ToList();
results[0].Add
(
This.Single( x => x.Id == rootId )
);
for (int level = 1; level <= maxDepth; level++)
{
results[level].AddRange
(
results[level-1].SelectMany
(
x => This.Where( y => y.ParentId == x.Id )
)
);
}
return results.SelectMany( x => x );
}