C# 迭代时从对象数组中删除元素

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

我有一个通过外部扩展迭代的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 = 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方法返回一个新的可枚举项,它不会更改调用它的可枚举项的状态。如何更改可枚举项的状态?你有一个例子吗?只需重新分配给自己<代码>元素=元素。跳过(位置)为什么你不能