在C中过滤集合#
我正在寻找一种非常快速的方式来过滤C#中的集合。我目前正在使用通用清单<对象>集合,但如果它们的性能更好,我可以使用其他结构。在C中过滤集合#
目前,我只是创建一个新的列表<对象>并循环通过原始列表。如果过滤标准匹配,我将一份副本放入新列表中。
有没有更好的方法来做到这一点?有没有一种方法可以过滤到位,因此不需要临时列表?
如果您正在使用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();
Where扩展方法返回IEnumerable
感谢Rafa的评论。 – David 2010-02-19 15:45:00
列表具有的FindAll方法,将做过滤为您和返回列表的子集。
在MSDN在这里有很大的代码示例:http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx
编辑:我写这之前,我有LINQ的一个很好的理解和Where()方法。如果我今天写这个,我可能会用上面提到的豪尔赫方法。尽管如此,FindAll方法仍然适用于.NET 2.0环境。
要做到这一点,你可以使用“List <>”类的RemoveAll方法以及一个自定义的“Predicate”类......但所有这些都是清理代码......在引擎盖下它是做同样的事情你是...但是,它做到了,所以你做同样的临时名单。
您可以使用IEnumerable来消除临时列表的需要。
public IEnumerable<T> GetFilteredItems(IEnumerable<T> collection)
{
foreach (T item in collection)
if (Matches<T>(item))
{
yield return item;
}
}
其中匹配是您的过滤方法的名称。你可以使用此类似:
IEnumerable<MyType> filteredItems = GetFilteredItems(myList);
foreach (MyType item in filteredItems)
{
// do sth with your filtered items
}
在需要的时候这将调用GetFilteredItems功能,在某些情况下,你不使用过滤集合中的所有项目,也可能提供一些好的性能增益。
如果您正在使用C#3.0,你可以使用LINQ
或者,如果你愿意的话,使用由C#3编译器提供的特殊查询语法:
var filteredList = from x in myList
where x > 7
select x;
这是一个代码块/一些列表过滤的例子,使用三种不同的方法,我放在一起显示基于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
使用Linq比使用提供给列表FindAll方法的谓词要慢。也必须小心Linq,因为在访问结果之前列表的列举实际上并未执行。这可能意味着,当您认为自己创建了过滤列表时,内容可能与您实际阅读时的预期内容有所不同。
如果您的列表非常大并且您正在反复过滤 - 您可以对过滤器属性的原始列表进行排序,二进制搜索以查找开始点和结束点。初始时间O(n * log(n)),然后O(log(n))。
标准过滤每次需要O(n)。
这将是非常快的。它是否会导致您的系统变慢?是一个*巨大的*名单?否则,我不会担心。 – 2008-08-25 15:13:00