C# 迭代时从对象数组中删除元素
我有一个通过外部扩展迭代的id/父级列表。 这个列表可以有大约11000行,这就是为什么我需要删除一些元素,以便只显示我需要的元素 元素列表:C# 迭代时从对象数组中删除元素,c#,arrays,C#,Arrays,我有一个通过外部扩展迭代的id/父级列表。 这个列表可以有大约11000行,这就是为什么我需要删除一些元素,以便只显示我需要的元素 元素列表: 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
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,
"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)));
}
公共静态IEnumerable RecursiveJoin(此
IEnumerable来源,
Func parentKeySelector,
Func childKeySelector,
Func结果选择器,
IComparer(比较器)
{
//防止每次RecursiveJoin调用多次枚举源
source=新链接列表(source);
//快速二进制搜索查找
SortedDictionary父项=新的SortedDictionary(比较器);
分类词典儿童
=新的分类词典(比较器);
foreach(源中的TSource元素)
{
父项[parentKeySelector(元素)]=元素;
链接列表;
TKey childKey=childKeySelector(元素);
if(!children.TryGetValue(childKey,out list))
{
children[childKey]=list=newlinkedlist();
}
list.AddLast(元素);
}
//初始化为null,否则编译器在单行赋值时会抱怨
Func childSelector=null;
childSelector=(TSource parent,int depth)=>
{
LinkedList innerChildren=null;
if(children.TryGetValue(parentKeySelector(parent),out innerChildren))
{
返回innerChildren.Select((子级,索引)
=>结果选择器(子级、索引、深度、子级选择器(子级、深度+1));
}
返回可枚举的.Empty();
};
返回source.Where(element=>!parents.ContainsKey(childKeySelector(element)))
.Select((元素,索引)=>resultSelector(元素,索引,0,子选择器(元素,1));
}
而不是
.Where(x => x.Id >= 5)
试一试
如果不知道ID,但知道索引(偏移到列表中),可以使用获取索引,它将索引作为第二个参数提供给where委托
.Where
(
(row, index) => row.Id > 5 //Filter on data
&& index != 11 //Filter on row index
)
或者您可以简单地这样做(效率稍低):
如果(根据您的编辑)正在查找子代和孙辈列表,给定父代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);
}
}
}
}
如果需要限制级别,可以尝试这种方法,这种方法效率较低,但可以明确每个孩子所处的级别以及何时停止搜索:
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 );
}
public静态IEnumerable getsubstants(this IEnumerable this,int rootId,int maxDepth)
{
var results=Enumerable.Range(0,maxDepth+1).Select(i=>newlist()).ToList();
结果[0]。添加
(
This.Single(x=>x.Id==rootId)
);
for(int level=1;level This.Where(y=>y.ParentId==x.Id)
)
);
}
返回结果。选择many(x=>x);
}
而不是
.Where(x => x.Id >= 5)
试一试
如果不知道ID,但知道索引(偏移到列表中),可以使用获取索引,它将索引作为第二个参数提供给where委托
.Where
(
(row, index) => row.Id > 5 //Filter on data
&& index != 11 //Filter on row index
)
或者您可以简单地这样做(效率稍低):
如果(根据您的编辑)正在查找子代和孙辈列表,给定父代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);
}
}
}
}
如果需要限制级别,可以尝试这种方法,这种方法效率较低,但可以明确每个孩子所处的级别以及何时停止搜索:
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 );
}
public静态IEnumerable getsubstants(this IEnumerable this,int rootId,int maxDepth)
{
var results=Enumerable.Range(0,maxDepth+1).Select(i=>newlist()).ToList();
结果[0]。添加
(
This.Single(x=>x.Id==rootId)
);
for(int level=1;level This.Where(y=>y.ParentId==x.Id)
)
);
}
返回结果。选择many(x=>x);
}
我只知道起始位置(根部),而不知道id 11。ID11我必须在递归函数中的一些逻辑之后找到它。我没有发布所有代码来简化我的帖子。我添加了第二个示例来演示如何根据行集索引进行过滤。John Wu,我更新了我的帖子。现在你会更好地理解我的需要。我会写一篇有更多细节的新文章。我不想删除SOF不建议的一个原因:递归搜索的另一个例子。我只知道起始位置(根),而不知道id 11。ID11我必须在递归函数中的一些逻辑之后找到它。我没有发布所有代码来简化我的帖子。我添加了第二个示例来演示如何根据行集索引进行过滤。John Wu,我更新了我的帖子。现在你会更好地理解我的需要。我会写一篇有更多细节的新文章。我不想删除SOF不建议的一个原因:递归搜索的另一个示例。LINQ的Skip方法返回一个新的枚举,它不会更改调用它的枚举的状态。如何更改枚举的状态?你有一个例子吗?只需重新分配给自己<代码>元素=元素。跳过(位置)为什么不能
其中(x=>x.Id!=7&&x.Id!=11)
?Skip
不跳过特定的元素索引,它从当前位置跳过指定数量的元素(并返回剩余的元素)。LINQ的Skip方法返回一个新的可枚举项,它不会更改调用它的可枚举项的状态。如何更改可枚举项的状态?你有一个例子吗?只需重新分配给自己<代码>元素=元素。跳过(位置)代码>为什么你不能