在C#中过滤集合

我正在寻找一种非常快速的方式来过滤在C#中的集合。 我目前正在使用通用的List <object>集合,但如果它们执行得更好,我可以使用其他结构。

目前,我只是创build一个新的List <object>,并循环通过原始列表。 如果过滤标准匹配,我把一份副本放入新列表中。

有一个更好的方法吗? 有没有办法过滤到位,所以没有临时名单要求?

如果你使用C#3.0,你可以使用linq,更好,更优雅的方式:

List<int> myList = GetListOfIntsFromSomewhere(); // This will filter out the list of ints that are > than 7, Where returns an // IEnumerable<T> so a call to ToList is required to convert back to a List<T>. List<int> filteredList = myList.Where( x => x > 7).ToList(); 

这里是一个代码块/例子的一些列表过滤使用三种不同的方法,我放在一起显示基于Lambda和LINQ的列表过滤。

 #region List Filtering static void Main(string[] args) { ListFiltering(); Console.ReadLine(); } private static void ListFiltering() { var PersonList = new List<Person>(); PersonList.Add(new Person() { Age = 23, Name = "Jon", Gender = "M" }); //Non-Constructor Object Property Initialization PersonList.Add(new Person() { Age = 24, Name = "Jack", Gender = "M" }); PersonList.Add(new Person() { Age = 29, Name = "Billy", Gender = "M" }); PersonList.Add(new Person() { Age = 33, Name = "Bob", Gender = "M" }); PersonList.Add(new Person() { Age = 45, Name = "Frank", Gender = "M" }); PersonList.Add(new Person() { Age = 24, Name = "Anna", Gender = "F" }); PersonList.Add(new Person() { Age = 29, Name = "Sue", Gender = "F" }); PersonList.Add(new Person() { Age = 35, Name = "Sally", Gender = "F" }); PersonList.Add(new Person() { Age = 36, Name = "Jane", Gender = "F" }); PersonList.Add(new Person() { Age = 42, Name = "Jill", Gender = "F" }); //Logic: Show me all males that are less than 30 years old. Console.WriteLine(""); //Iterative Method Console.WriteLine("List Filter Normal Way:"); foreach (var p in PersonList) if (p.Gender == "M" && p.Age < 30) Console.WriteLine(p.Name + " is " + p.Age); Console.WriteLine(""); //Lambda Filter Method Console.WriteLine("List Filter Lambda Way"); foreach (var p in PersonList.Where(p => (p.Gender == "M" && p.Age < 30))) //.Where is an extension method Console.WriteLine(p.Name + " is " + p.Age); Console.WriteLine(""); //LINQ Query Method Console.WriteLine("List Filter LINQ Way:"); foreach (var v in from p in PersonList where p.Gender == "M" && p.Age < 30 select new { p.Name, p.Age }) Console.WriteLine(v.Name + " is " + v.Age); } private class Person { public Person() { } public int Age { get; set; } public string Name { get; set; } public string Gender { get; set; } } #endregion 

List有FindAll方法,它将为你做过滤并返回列表的一个子集。

msdn在这里有一个很好的代码示例: http : //msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

编辑:我之前,我已经很好地理解了Linq和Where()方法。 如果我今天写这个,我可能会用上面提到的豪尔赫方法。 尽pipe如此,FindAll方法仍然可以在.NET 2.0环境中使用。

您可以使用IEnumerable来消除临时列表的需要。

 public IEnumerable<T> GetFilteredItems(IEnumerable<T> collection) { foreach (T item in collection) if (Matches<T>(item)) { yield return item; } } 

其中Matches是您的过滤方法的名称。 你可以像这样使用它:

 IEnumerable<MyType> filteredItems = GetFilteredItems(myList); foreach (MyType item in filteredItems) { // do sth with your filtered items } 

这将在需要时调用GetFilteredItems函数,并且在某些情况下,您不使用已过滤集合中的所有项目,它可能会提供一些良好的性能增益。

要做到这一点,你可以使用“List <>”类的RemoveAll方法以及一个自定义的“Predicate”类…但所有这些都是清理代码…在引擎盖下它是做同样的事情你是…但是,它做到位,所以你做同样的临时名单。

您可以使用List的FindAll方法,提供一个委托进行过滤。 虽然,我同意@ IainMH ,除非是一个巨大的名单,否则不值得担心自己。

使用Linq比使用提供给List FindAll方法的谓词要慢得多。 也不得不小心使用Linq,因为在访问结果之前,列表的枚举实际上并没有执行。 这可能意味着,如果您认为已经创build了过滤列表,则内容可能与您实际阅读时所期望的内容有所不同。

如果你使用C#3.0,你可以使用linq

或者,如果您愿意,可以使用C#3编译器提供的特殊查询语法:

 var filteredList = from x in myList where x > 7 select x; 

如果您的列表非常大,并且您正在重复筛选 – 可以对筛选器属性的原始列表进行sorting,二进制search以查找开始点和结束点。

初始时间O(n * log(n))然后是O(log(n))。

标准过滤每次将花费O(n)。