LINQ:RemoveAll并删除元素

时间:2012-04-16 17:05:27

标签: c# linq removeall

从列表中删除与某些条件相匹配的项目的最简单方法是获取这些项目。

我可以从几个方面思考,我不知道哪个是最好的:

var subList = list.Where(x => x.Condition);
list.RemoveAll(x => x.Condition);

var subList = list.Where(x => x.Condition);
list.RemoveAll(x => subList.Contains(x));

这是最好的方法吗?如果是,哪一个?如果不是,我该怎么做?

4 个答案:

答案 0 :(得分:5)

出于可读性目的,我会选择第一个选项,并注意您应首先实现列表,否则您将丢失您尝试在下一行选择的项目:

var sublist = list.Where(x => x.Condition).ToArray();
list.RemoveAll(x => x.Condition);

第二个例子是O(n ^ 2),没有理由,最后一个是完全正常,但可读性较差。

编辑:现在我重读了你的最后一个例子,请注意,因为它现在写的将取出所有其他项目。您错过了条件检查,删除行实际上应该是list.RemoveAt(i--);,因为i+1元素在删除后成为i元素,并且当您增加i时你正在跳过它。

答案 1 :(得分:4)

我喜欢使用函数式编程方法(只做新事物,不要修改现有的东西)。 ToLookup的一个优点是,您可以处理多个项目的双向拆分。

ILookup<bool, Customer> lookup = list.ToLookup(x => x.Condition);
List<Customer> sublist = lookup[true].ToList();
list = lookup[false].ToList();

或者如果您需要修改原始实例......

list.Clear();
list.AddRange(lookup[false]);

答案 2 :(得分:0)

我一直在找同样的事情。我想在我删除的项目上记录一些错误。由于我添加了一大堆验证规则,因此删除和日志调用应该尽可能简洁。

我做了以下扩展方法:

public static class ListExtensions
{
    /// <summary>
    /// Modifies the list by removing all items that match the predicate. Outputs the removed items.
    /// </summary>
    public static void RemoveWhere<T>(this List<T> input, Predicate<T> predicate, out List<T> removedItems)
    {
        removedItems = input.Where(item => predicate(item)).ToList();
        input.RemoveAll(predicate);
    }

    /// <summary>
    /// Modifies the list by removing all items that match the predicate. Calls the given action for each removed item.
    /// </summary>
    public static void RemoveWhere<T>(this List<T> input, Predicate<T> predicate, Action<T> actionOnRemovedItem)
    {
        RemoveWhere(input, predicate, out var removedItems);
        foreach (var removedItem in removedItems) actionOnRemovedItem(removedItem);
    }
}

使用示例:

items.RemoveWhere(item => item.IsWrong, removedItem =>
    errorLog.AppendLine($"{removedItem} was wrong."));

答案 3 :(得分:0)

第一个选项是好的,但是它会使集合运行两次。您可以通过执行谓词中的其他逻辑来一次运行:

        var removedItems = new List<Example>();
        list.RemoveAll(x =>
        {
            if (x.Condition)
            {
                removedItems.Add(x);
                return true;
            }

            return false;
        });

为了方便起见,您也可以将其包装到扩展程序中

public static class ListExtensions
{
    public static int RemoveAll<T>(this List<T> list, Predicate<T> predicate, Action<T> action)
    {
        return list.RemoveAll(item =>
        {
            if (predicate(item))
            {
                action(item);
                return true;
            }

            return false;
        });
    }
}

并像这样使用:

        var removedItems = new List<Example>();
        list.RemoveAll(x => x.Condition, x => removedItems.Add(x));