2008-08-25 14 views
92

C#でコレクションをフィルタリングする非常に高速な方法を探しています。私は現在、汎用リスト<オブジェクト>のコレクションを使用していますが、パフォーマンスが優れている場合は他の構造を使用しています。C#でコレクションをフィルタリングする

現在、新しいリスト<オブジェクト>を作成し、元のリストをループしています。フィルタリング基準が一致する場合は、コピーを新しいリストに入れます。

これを行うより良い方法はありますか?一時的なリストが必要ないようにフィルタリングする方法はありますか?

+0

これはすばらしく速くなるでしょう。あなたのシステムが遅くなっていますか? *巨大なリストですか?それ以外の場合、私は心配しません。 –

答えて

151

あなたはずっといいと方法よりエレガントな、あなたはLINQを使用することができますC#3.0を使用している場合:

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拡張メソッドは、List ではなく、IEnumerable を返します。それはする必要があります:myList.Where(x => x> 7).ToList() –

+0

あなたのコメントのおかげでラファ。 – David

+1

これは文字列によるフィルタリングの仕組みです。 "ch"で始まる文字列のリスト内のすべての項目を見つけるように。 – joncodo

9

一覧をあなたのためのフィルタリングを行うと、リストのサブセットを返しますFindAllメソッドを持っています。

MSDNは、ここでは偉大なコード例があります。http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

編集:私はLINQのとどこで()メソッドをよく理解していた前に、私はこれを書きました。もし私が今日これを書いていたら、私はおそらく上で述べた方法を使うだろう。 FindAllメソッドは、.NET 2.0環境で動かなくても動作します。

+1

Linqは問題ありませんが、IEnumerableに依存していないFindAllとフィルタ拡張メソッド(配列はそれらの束があります)はパフォーマンスが重要なシナリオではまだ意味があります。 (FWIW、LinqやIEnumerableで必要とされる7〜50倍の時間がかかる) – Philm

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; 
    } 
} 

ここで、Matchesはフィルタメソッドの名前です。そして、あなたはこのように使用することができます。

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

必要なときにこれはGetFilteredItems関数を呼び出しますし、あなたがフィルター処理されたコレクション内のすべてのアイテムを使用していないいくつかのケースでは、それはいくつかの良いパフォーマンスが向上することがあります。

2

リストのFindAllメソッドを使用して、フィルタを適用するデリゲートを提供できます。しかし、私は@IainMHに同意するのは、それが巨大なリストでなければあまり心配する価値はないということです。

1

あなたがC#3.0あなたがC#3コンパイラによって提供される特別なクエリ構文を使用し、

それとも、あなたが好むならLINQを使用することができますを使用している場合:

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

ここでは、LambdaおよびLINQベースのリストフィルタを表示するために3つの異なる方法を使用したリストフィルタのコードブロック/例を示します。

#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の使用は、Lists FindAllメソッドに提供された述語を使用するよりも比較的緩慢です。また、結果にアクセスするまで実際には実行されないので、Linqに注意する必要があります。これは、フィルタリングされたリストを作成したと思うと、内容が実際に読み込まれたときの内容と異なる場合があることを意味します。

0

あなたのリストは非常に大きいですし、繰り返しフィルタリングしている場合 - あなたは開始点と終了点を見つけるために、フィルタ属性にバイナリ検索を元のリストを並べ替えることができます。

初期時間はO(n *ログ(N))をO(ログ(N))。

標準フィルタリングはO(n)の各時間がかかります。

関連する問題