我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。

你不能在foreach (var element in X)中使用.Remove(element)(因为它会导致Collection被修改;枚举操作可能无法执行。例外)……你也不能使用for (int I = 0;i < elements.Count();i++)和. removeat (i),因为它破坏了你在集合中相对于i的当前位置。

有没有一种优雅的方式来做到这一点?


当前回答

在泛型列表上使用ToArray()可以在泛型列表上执行Remove(item):

        List<String> strings = new List<string>() { "a", "b", "c", "d" };
        foreach (string s in strings.ToArray())
        {
            if (s == "b")
                strings.Remove(s);
        }

其他回答

一个简单而直接的解决方案:

在你的集合上使用一个标准的for循环,并使用RemoveAt(i)来删除元素。

在遍历列表时从列表中删除项的最佳方法是使用RemoveAll()。但是人们编写的主要问题是他们必须在循环中做一些复杂的事情和/或有复杂的比较情况。

解决方案是仍然使用RemoveAll(),但使用以下符号:

var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item => 
{
    // Do some complex operations here
    // Or even some operations on the items
    SomeFunction(item);
    // In the end return true if the item is to be removed. False otherwise
    return item > 5;
});

使用for循环反向迭代列表:

for (int i = safePendingList.Count - 1; i >= 0; i--)
{
    // some code
    // safePendingList.RemoveAt(i);
}

例子:

var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
    if (list[i] > 5)
        list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));

或者,你可以使用RemoveAll方法和一个谓词来测试:

safePendingList.RemoveAll(item => item.Value == someValue);

下面是一个简单的例子:

var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));

假设predicate是一个元素的布尔属性,如果它为真,则该元素应该被移除:

        int i = 0;
        while (i < list.Count())
        {
            if (list[i].predicate == true)
            {
                list.RemoveAt(i);
                continue;
            }
            i++;
        }

我的方法是,首先创建一个索引列表,这些索引应该被删除。然后,我遍历索引并从初始列表中删除项目。它看起来是这样的:

var messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);

if (customMessageList != null && customMessageList.Count > 0)
{
    // Create list with positions in origin list
    List<int> positionList = new List<int>();
    foreach (var message in customMessageList)
    {
        var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
        if (position != -1)
            positionList.Add(position);
    }
    // To be able to remove the items in the origin list, we do it backwards
    // so that the order of indices stays the same
    positionList = positionList.OrderByDescending(p => p).ToList();
    foreach (var position in positionList)
    {
        messageList.RemoveAt(position);
    }
}