[英]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.