在 C# 中过滤集合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Filtering collections in C#
提问by Jason Z
I am looking for a very fast way to filter down a collection in C#. I am currently using generic List<object> collections, but am open to using other structures if they perform better.
我正在寻找一种非常快速的方法来过滤 C# 中的集合。我目前正在使用通用 List<object> 集合,但如果它们表现更好,我愿意使用其他结构。
Currently, I am just creating a new List<object> and looping thru the original list. If the filtering criteria matches, I put a copy into the new list.
目前,我只是创建一个新的 List<object> 并循环遍历原始列表。如果过滤条件匹配,我将一个副本放入新列表中。
Is there a better way to do this? Is there a way to filter in place so there is no temporary list required?
有一个更好的方法吗?有没有办法就地过滤,所以不需要临时列表?
采纳答案by Jorge Córdoba
If you're using C# 3.0 you can use linq, way better and way more elegant:
如果您使用的是 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();
If you can't find the .Where
, that means you need to import using System.Linq;
at the top of your file.
如果找不到.Where
,则意味着您需要using System.Linq;
在文件顶部导入。
回答by Mykroft
List<T>
has a FindAll
method that will do the filtering for you and return a subset of the list.
List<T>
有一个FindAll
方法可以为您进行过滤并返回列表的一个子集。
MSDN has a great code example here: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx
MSDN 有一个很好的代码示例:http: //msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx
EDIT: I wrote this before I had a good understanding of LINQ and the Where()
method. If I were to write this today i would probably use the method Jorge mentions above. The FindAll
method still works if you're stuck in a .NET 2.0 environment though.
编辑:我在对 LINQ 和Where()
方法有很好的理解之前写了这篇文章。如果我今天写这篇文章,我可能会使用上面 Jorge 提到的方法。FindAll
如果您被困在 .NET 2.0 环境中,该方法仍然有效。
回答by Adam Haile
To do it in place, you can use the RemoveAll method of the "List<>" class along with a custom "Predicate" class...but all that does is clean up the code... under the hood it's doing the same thing you are...but yes, it does it in place, so you do same the temp list.
要做到这一点,您可以使用“List<>”类的 RemoveAll 方法以及一个自定义的“Predicate”类......但所做的只是清理代码......在幕后它正在做同样的事情你是什么......但是是的,它就位,所以你做同样的临时列表。
回答by Serhat Ozgel
You can use IEnumerable to eliminate the need of a temp list.
您可以使用 IEnumerable 来消除对临时列表的需要。
public IEnumerable<T> GetFilteredItems(IEnumerable<T> collection)
{
foreach (T item in collection)
if (Matches<T>(item))
{
yield return item;
}
}
where Matches is the name of your filter method. And you can use this like:
其中 Matches 是过滤器方法的名称。你可以像这样使用它:
IEnumerable<MyType> filteredItems = GetFilteredItems(myList);
foreach (MyType item in filteredItems)
{
// do sth with your filtered items
}
This will call GetFilteredItems function when needed and in some cases that you do not use all items in the filtered collection, it may provide some good performance gain.
这将在需要时调用 GetFilteredItems 函数,并且在某些情况下您不使用过滤集合中的所有项目,它可能会提供一些良好的性能增益。
回答by bdukes
You can use the FindAllmethod of the List, providing a delegate to filter on. Though, I agree with @IainMHthat it's not worth worrying yourself too much unless it's a huge list.
您可以使用List的FindAll方法,提供一个委托进行过滤。尽管如此,我同意@ IainMH 的观点,除非它是一个巨大的清单,否则不值得让自己担心太多。
回答by Tom Lokhorst
If you're using C# 3.0 you can use linq
如果您使用的是 C# 3.0,则可以使用 linq
Or, if you prefer, use the special query syntax provided by the C# 3 compiler:
或者,如果您愿意,也可以使用 C# 3 编译器提供的特殊查询语法:
var filteredList = from x in myList
where x > 7
select x;
回答by Jon Erickson
Here is a code block / example of some list filtering using three different methods that I put together to show Lambdas and LINQ based list filtering.
这是使用三种不同方法的一些列表过滤的代码块/示例,我将它们放在一起以显示基于 Lambdas 和 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 = "Hyman", 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
回答by gouldos
Using LINQ is relatively much slower than using a predicate supplied to the Lists FindAll
method. Also be careful with LINQ as the enumeration of the list
is not actually executed until you access the result. This can mean that, when you think you have created a filtered list, the content may differ to what you expected when you actually read it.
使用 LINQ 比使用提供给 ListsFindAll
方法的谓词要慢得多。还要注意 LINQ,因为在list
您访问结果之前,实际上不会执行的枚举。这可能意味着,当您认为已创建过滤列表时,内容可能与您实际阅读时的预期有所不同。
回答by Daniel Roberts
If your list is very big and you are filtering repeatedly - you can sort the original list on the filter attribute, binary search to find the start and end points.
如果您的列表非常大并且您正在重复过滤 - 您可以根据过滤器属性对原始列表进行排序,二进制搜索以找到起点和终点。
Initial time O(n*log(n)) then O(log(n)).
初始时间 O(n*log(n)) 然后 O(log(n))。
Standard filtering will take O(n) each time.
标准过滤每次都需要 O(n)。