2008-08-25 147 views
92

我正在尋找一種非常快速的方式來過濾C#中的集合。我目前正在使用通用清單<對象>集合,但如果它們的性能更好,我可以使用其他結構。在C中過濾集合#

目前,我只是創建一個新的列表<對象>並循環通過原始列表。如果過濾標準匹配,我將一份副本放入新列表中。

有沒有更好的方法來做到這一點?有沒有一種方法可以過濾到位,因此不需要臨時列表?

+0

這將是非常快的。它是否會導致您的系統變慢?是一個*巨大的*名單?否則,我不會擔心。 – 2008-08-25 15:13:00

回答

151

如果您正在使用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(); 
+16

Where擴展方法返回IEnumerable ,而不是列表。它應該是:myList.Where(x => x> 7).ToList() – 2010-01-21 05:29:32

+0

感謝Rafa的評論。 – David 2010-02-19 15:45:00

9

列表具有的FindAll方法,將做過濾爲您和返回列表的子集。

在MSDN在這裏有很大的代碼示例:http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

編輯:我寫這之前,我有LINQ的一個很好的理解和Where()方法。如果我今天寫這個,我可能會用上面提到的豪爾赫方法。儘管如此,FindAll方法仍然適用於.NET 2.0環境。

3

要做到這一點,你可以使用「List <>」類的RemoveAll方法以及一個自定義的「Predicate」類......但所有這些都是清理代碼......在引擎蓋下它是做同樣的事情你是...但是,它做到了,所以你做同樣的臨時名單。

6

您可以使用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功能,在某些情況下,你不使用過濾集合中的所有項目,也可能提供一些好的性能增益。

2

您可以使用List的FindAll方法,提供要過濾的委託。雖然,我同意@IainMH,除非它是一個巨大的列表,否則不值得擔心自己。

1

如果您正在使用C#3.0,你可以使用LINQ

或者,如果你願意的話,使用由C#3編譯器提供的特殊查詢語法:

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

這是一個代碼塊/一些列表過濾的例子,使用三種不同的方法,我放在一起顯示基於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 
2

使用Linq比使用提供給列表FindAll方法的謂詞要慢。也必須小心Linq,因爲在訪問結果之前列表的列舉實際上並未執行。這可能意味着,當您認爲自己創建了過濾列表時,內容可能與您實際閱讀時的預期內容有所不同。

0

如果您的列表非常大並且您正在反覆過濾 - 您可以對過濾器屬性的原始列表進行排序,二進制搜索以查找開始點和結束點。初始時間O(n * log(n)),然後O(log(n))。

標準過濾每次需要O(n)。