从集合中查找和删除项目

从集合中删除集合的最佳方法是什么,但仍保留在单独集合中删除的项目?

我写了一个扩展方法来做到这一点,但我认为必须有一个更好的方法。 这是我的function:

public static List FindAndRemove(this List lst, Predicate match) { List ret = lst.FindAll(match); lst.RemoveAll(match); return ret; } 

你会像这样使用它:

 List myList = new List(); myList.Add("ABC"); myList.Add("DEF"); myList.Add("ABC"); List removed = myList.FindAndRemove(x => x == "ABC"); // myList now contains 1 item (DEF) // removed now contains 2 items (ABC, ABC) 

我不是100%肯定在FindAllRemoveAll方法中幕后发生的事情,但我想更好的方法是以某种方式将项目从一个列表“转移”到另一个列表。

到目前为止,Op的答案是提出的和建议的解决方案中最好的。 这是我机器上的时间:

 public static class Class1 { // 21ms on my machine public static List FindAndRemove(this List lst, Predicate match) { List ret = lst.FindAll(match); lst.RemoveAll(match); return ret; } // 538ms on my machine public static List MimoAnswer(this List lst, Predicate match) { var ret = new List(); 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 GuvanteSuggestion(this IList list, Func predicate) { var removals = new List(); 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 ints = Enumerable.Range(1, 100000).ToList(); IEnumerable enumerable = ints.GuvanteSuggestion(i => i % 2 == 0); Assert.That(enumerable.Count(), Is.EqualTo(50000)); } } 

我不同意它是最有效的 – 你在列表的每个元素上调用谓词match两次。

我这样做:

  var ret = new List(); var remaining = new List(); 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已经涵盖了它。