c# - 如何在同时删除项目的同时遍历列表?

标签 c# list iteration

我正在尝试寻找一种优雅的方式来迭代列表,同时删除项目。
I know this solution .但是我的条件更难一些:

  • 此处所有单线程
  • 迭代必须向前
  • 每个项目都必须恰好一次处理。
  • 多个和随机项目可以在处理 1 个项目时移除。
  • 项目是复杂且智能的对象。他们执行一个自定义方法,它可以决定删除某些项目(0 到全部)。
  • (添加和插入也可以发生,但现在这并不重要,如果有办法同时处理,那就太好了)

问题:这可能吗?如果是,怎么办?


我想将对象标记已删除/不活动。等我以后再迭代的时候,我就把他们去掉,不叫他们做事。迭代会经常重复,这就是为什么每个对象在每次迭代中都必须恰好转一圈。那行得通吗?


这就是我现在处理事情的方式。它并不完美,但我希望能为您提供提示。

伪代码:

class Foo
{
    public void DoStuff()
    {
        // do other stuff

        if (condition)
            Kill(x); // should result in list.RemoveAt(x) somehow
    }
}

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        List<Foo> list = new List<Foo>();
        for (int i = 0; i < 15; i++)
            list.Add(new Foo());

        for (int i = 0; i < list.Count; i++)
            list[i].DoStuff();

        Console.ReadKey();
    }
}


(这不是 XY 问题。我确定。多年来我一直在想这个问题,我决定最终找到一个可靠的解决方案。我正在为此使用 C# 工作。这不是恶作剧. 如果它像这样接缝,我很抱歉。)

感谢您的帮助!

最佳答案

您可以在此处使用 ObservableCollection,以便迭代集合的代码可以检测集合在迭代时何时以及如何发生变异。通过使用 ObservableCollection,迭代代码可以在当前索引之前添加项目时递增索引,或者在当前索引之前移除项目时递减索引。

public static IEnumerable<T> IterateWhileMutating<T>(
    this ObservableCollection<T> list)
{
    int i = 0;
    NotifyCollectionChangedEventHandler handler = (_, args) =>
    {
        switch (args.Action)
        {
            case NotifyCollectionChangedAction.Add:
                if (args.NewStartingIndex <= i)
                    i++;
                break;
            case NotifyCollectionChangedAction.Move:
                if (args.NewStartingIndex <= i)
                    i++;
                if (args.OldStartingIndex <= i) //note *not* else if
                    i--;
                break;
            case NotifyCollectionChangedAction.Remove:
                if (args.OldStartingIndex <= i)
                    i--;
                break;
            case NotifyCollectionChangedAction.Reset:
                i = int.MaxValue;//end the sequence
                break;
            default:
                //do nothing
                break;
        }
    };
    try
    {
        list.CollectionChanged += handler;
        for (i = 0; i < list.Count; i++)
        {
            yield return list[i];
        }
    }
    finally
    {
        list.CollectionChanged -= handler;
    }
}

代码取自this other answer of mine .它包含有关在改变序列时迭代序列的后果的其他切线信息,以及有关此代码及其设计决策含义的一些其他解释。

关于c# - 如何在同时删除项目的同时遍历列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24807799/

相关文章:

c# - 如何获取 Active Directory 组中的组列表

C#的编译器设计——前向引用

c# - 具有多选的 OpenFileDialog 框,.filenames 多次接收相同的名称

c# - 庞大的长列表和搜索最近的元素

python - 在python中制作没有引用的列表列表

c# - Microsoft Graph 无需每次或 token 长时间登录

c# - 从异步函数返回的 IEnumerable<T> 创建 List<T>

python - 映射单个函数比两次映射两个单独的函数慢?

algorithm - 简单 : Solve T(n)=T(n-1)+n by Iteration Method

ruby-on-rails - 通过关系迭代 has_many 并包含连接表中的数据