在 C 语言中筛选集合#

Filtering collections in C#

提问人:Jason Z 提问时间:8/25/2008 最后编辑:johnthagenJason Z 更新时间:1/11/2022 访问量:368641

问:

我正在寻找一种非常快速的方法来过滤 C# 中的集合。我目前正在使用泛型集合,但如果它们性能更好,我愿意使用其他结构。List<object>

目前,我只是在原始列表中创建一个新的循环列表。如果过滤条件匹配,我会将副本放入新列表中。List<object>

有没有更好的方法可以做到这一点?有没有办法就地过滤,这样就不需要临时列表了?

C# 集合 筛选

评论

1赞 Iain Holder 8/25/2008
这将是极快的。它是否导致您的系统变慢?是一个巨大的清单吗?否则,我不会担心。

答:

304赞 Jorge Córdoba 8/25/2008 #1

如果你使用的是 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();

如果找不到 ,则表示需要在文件顶部导入。.Whereusing System.Linq;

评论

1赞 joncodo 10/27/2011
这如何用于按字符串过滤。就像在以“ch”开头的字符串列表中查找所有项目一样
3赞 Mike G 1/20/2012
@JonathanO 您可以在 Func 中使用方法。listOfStrings.Where(s => s.StartsWith(“ch”))。ToList();
1赞 CosmicGiant 7/27/2016
有没有办法使 linq 查询客观化?例如,使用 而不是 ?.Where(predefinedQuery).Where(x => x > 7)
2赞 Don 6/9/2017
@AlmightyR:只需将其定义为接受一个参数的方法。前任:。那么你会工作正常。public bool predefinedQuery(int x) { return x > 7; }.Where(predefinedQuery)
21赞 Mykroft 8/25/2008 #2

List<T>有一个方法,可以为您进行筛选并返回列表的子集。FindAll

MSDN这里有一个很好的代码示例:http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

编辑:我在对LINQ和方法有很好的理解之前就写了这篇文章。如果我今天要写这篇文章,我可能会使用豪尔赫上面提到的方法。但是,如果您被困在 .NET 2.0 环境中,该方法仍然有效。Where()FindAll

评论

6赞 Philm 5/10/2017
Linq 很好,但至少慢了一个数量级,因此不依赖于 IEnumerable 的 FindAll 和筛选扩展方法(例如数组有一堆)对于性能很重要的方案仍然有意义。(FWIW,我得到的结果是 Linq 和/或 IEnumerable 需要的 7 到 50 倍)
0赞 Ran Lottem 2/10/2019
这不是公认的答案是有原因的吗?它似乎更快,语法更清晰(没有 toList())调用。
4赞 Adam Haile 8/25/2008 #3

若要就地执行此操作,可以使用“List<>”类的 RemoveAll 方法以及自定义的“Predicate”类...但所做的只是清理代码......在引擎盖下,它正在做和你一样的事情......但是,是的,它做到了这一点,所以你对临时列表也做了同样的事情。

8赞 Serhat Ozgel 8/25/2008 #4

可以使用 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 函数,在某些情况下,您不使用筛选集合中的所有项,它可能会提供一些良好的性能提升。

4赞 bdukes 8/25/2008 #5

可以使用 List 的 FindAll 方法,提供要筛选的委托。不过,我同意@IainMH的观点,除非这是一个庞大的清单,否则不值得太担心自己。

4赞 Tom Lokhorst 8/25/2008 #6

如果您使用的是 C# 3.0,则可以使用 linq

或者,如果您愿意,请使用 C# 3 编译器提供的特殊查询语法:

var filteredList = from x in myList
                   where x > 7
                   select x;
23赞 Jon Erickson 8/25/2008 #7

下面是一个代码块/示例,使用三种不同的方法进行列表筛选,我将它们放在一起来展示基于 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 = "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
3赞 gouldos 10/12/2010 #8

使用 LINQ 比使用提供给 Lists 方法的谓词要慢得多。另外,要小心 LINQ,因为在访问结果之前,不会实际执行 的枚举。这可能意味着,当您认为自己创建了过滤列表时,内容可能与实际阅读时的预期不同。FindAlllist

1赞 Daniel Roberts 6/30/2016 #9

如果你的列表非常大,并且你正在重复筛选 - 你可以在filter属性上对原始列表进行排序,二叉搜索来查找起点和终点。

初始时间 O(n*log(n)) 然后 O(log(n))。

标准过滤每次都需要 O(n)。