[英]Find And Remove Items From Collection
从集合中删除集合的最佳方法是什么,但仍保留在单独集合中删除的项目?
我写了一个扩展方法来做到这一点,但我认为必须有一个更好的方法。 这是我的功能:
public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match)
{
List<T> ret = lst.FindAll(match);
lst.RemoveAll(match);
return ret;
}
你会像这样使用它:
List<String> myList = new List<String>();
myList.Add("ABC");
myList.Add("DEF");
myList.Add("ABC");
List<String> removed = myList.FindAndRemove(x => x == "ABC");
// myList now contains 1 item (DEF)
// removed now contains 2 items (ABC, ABC)
我不是100%确定在FindAll
和RemoveAll
方法中幕后发生的事情,但我想更好的方法是以某种方式将项目从一个列表“转移”到另一个列表。
到目前为止,Op的答案是提出和建议的解决方案中最好的。 这是我机器上的时间:
public static class Class1
{
// 21ms on my machine
public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match)
{
List<T> ret = lst.FindAll(match);
lst.RemoveAll(match);
return ret;
}
// 538ms on my machine
public static List<T> MimoAnswer<T>(this List<T> lst, Predicate<T> match)
{
var ret = new List<T>();
int i = 0;
while (i < lst.Count)
{
T t = lst[i];
if (!match(t))
{
i++;
}
else
{
lst.RemoveAt(i);
ret.Add(t);
}
}
return ret;
}
// 40ms on my machine
public static IEnumerable<T> GuvanteSuggestion<T>(this IList<T> list, Func<T, bool> predicate)
{
var removals = new List<Action>();
foreach (T item in list.Where(predicate))
{
T copy = item;
yield return copy;
removals.Add(() => list.Remove(copy));
}
// this hides the cost of processing though the work is still expensive
Task.Factory.StartNew(() => Parallel.ForEach(removals, remove => remove()));
}
}
[TestFixture]
public class Tester : PerformanceTester
{
[Test]
public void Test()
{
List<int> ints = Enumerable.Range(1, 100000).ToList();
IEnumerable<int> enumerable = ints.GuvanteSuggestion(i => i % 2 == 0);
Assert.That(enumerable.Count(), Is.EqualTo(50000));
}
}
我不同意它是最有效的 - 你在列表的每个元素上调用谓词match
两次。
我这样做:
var ret = new List<T>();
var remaining = new List<T>();
foreach (T t in lst) {
if (match(t))
{
ret.Add(t);
}
else
{
remaining.Add(t);
}
}
lst.Clear();
lst.AddRange(remaining);
return ret;
根据集合的大小,您可能希望将其实现为HashSet而不是List。 在足够大的集合中(根据我的经验,有多大“足够”在某种程度上依赖于集合中的内容),HashSets在查找内部项目时可以比列表更快,更快。
您应该尝试将原始列表分成两个新列表。 实现应该适用于任何IEnumerable,而不仅仅是列表,并且应该假定源是不可变的。 请参阅有关分区的这篇文章: LINQ分区列表到8个成员的列表 。 我认为MoreLinq已经涵盖了它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.