繁体   English   中英

LINQ:RemoveAll并删除元素

[英]LINQ: RemoveAll and get elements removed

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

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

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));

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

我喜欢使用函数式编程方法(只做新事物,不要修改现有的东西)。 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]);

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

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

第二个例子是O(n ^ 2)无缘无故,最后一个是完美的,但可读性较差。

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

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

我做了以下扩展方法:

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."));

第一个选项很好,但是它会在集合上进行两次运行。 您可以通过执行谓词中的附加逻辑在一次运行中执行此操作:

        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));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM