174

C# でコレクションをフィルター処理する非常に高速な方法を探しています。私は現在ジェネリックList<object>コレクションを使用していますが、パフォーマンスが向上する場合は、他の構造を使用することにオープンです。

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

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

4

9 に答える 9

281

C# 3.0 を使用している場合は、linq を使用できます。これは、はるかに優れており、よりエレガントです。

List<int> myList = GetListOfIntsFromSomewhere();

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

が見つからない場合は、ファイルの先頭.Whereにインポートする必要があることを意味します。using System.Linq;

于 2008-08-25T15:13:51.927 に答える
21

これは、ラムダと 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
于 2008-08-25T15:38:11.993 に答える
17

List<T>にはFindAll、フィルタリングを行い、リストのサブセットを返すメソッドがあります。

MSDN には素晴らしいコード例があります: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

Where()編集:LINQとメソッドをよく理解する前にこれを書きました。今日これを書くとしたら、ホルヘが上で述べた方法をおそらく使用するでしょう。FindAllただし、.NET 2.0 環境で立ち往生している場合でも、この方法は機能します。

于 2008-08-25T15:14:40.303 に答える
8

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 関数が呼び出され、フィルター処理されたコレクション内のすべてのアイテムを使用しない場合、パフォーマンスが向上する可能性があります。

于 2008-08-25T15:16:03.107 に答える
4

その場でそれを行うには、「List<>」クラスのRemoveAllメソッドをカスタムの「Predicate」クラスとともに使用できます...しかし、それはコードをクリーンアップするだけです...フードの下では同じことをしていますあなたは...しかし、はい、それはその場でそれを行うので、一時リストと同じことをします.

于 2008-08-25T15:15:41.267 に答える
4

List のFindAllメソッドを使用して、フィルター処理するデリゲートを提供できます。ただし、巨大なリストでない限り、あまり心配する価値はないという@IainMHに同意します。

于 2008-08-25T15:16:23.090 に答える
3

FindAllLINQの使用は、Listsメソッドに提供された述語を使用するよりも比較的低速です。listまた、結果にアクセスするまでの列挙は実際には実行されないため、LINQには注意してください。これは、フィルタリングされたリストを作成したと思ったときに、実際に読んだときに期待した内容とは異なる可能性があることを意味します。

于 2010-10-12T15:04:15.380 に答える
3

C# 3.0 を使用している場合は、linq を使用できます

または、必要に応じて、C# 3 コンパイラが提供する特別なクエリ構文を使用します。

var filteredList = from x in myList
                   where x > 7
                   select x;
于 2008-08-25T15:23:04.540 に答える
1

リストが非常に大きく、繰り返しフィルタリングしている場合は、フィルタ属性で元のリストをソートし、二分探索で開始点と終了点を見つけることができます。

初期時間 O(n*log(n)) 次に O(log(n))。

標準のフィルタリングでは、毎回 O(n) かかります。

于 2016-06-30T11:21:53.267 に答える