Фильтрация коллекций в C #

Я ищу очень быстрый способ отфильтровать коллекцию в C #. В настоящее время я использую универсальные коллекции List <object>, но я открыт для использования других структур, если они работают лучше.

В настоящее время я просто создаю новый List <object> и перебираю исходный список. Если критерии фильтрации соответствуют, я помещаю копию в новый список.

Есть лучший способ это сделать? Есть ли способ фильтрации на месте, так что временный список не требуется?

25.08.2008 15:11:10
Это будет невероятно быстро. Это вызывает замедление вашей системы? Это огромный список? Иначе я бы не волновался.
Iain Holder 25.08.2008 15:13:00
9 ОТВЕТОВ
РЕШЕНИЕ

Если вы используете 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, это означает, что вам нужно импортировать using System.Linq;в начало вашего файла.

228
22.01.2019 00:10:28
Метод расширения Where возвращает IEnumerable <T>, а не List <T>. Это должно быть: myList.Where (x => x> 7) .ToList ()
Rafa Castaneda 21.01.2010 05:29:32
Как это работает для фильтрации по строкам. Как найти все элементы в списке строк, которые начинаются с "ch"
joncodo 27.10.2011 14:38:27
@JonathanO Вы можете использовать методы внутри Func. listOfStrings.Where (s => s.StartsWith ("ch")). ToList ();
Mike G 20.01.2012 13:58:26
Есть ли способ объективировать запросы linq? Например, использовать .Where(predefinedQuery)вместо использования .Where(x => x > 7)?
XenoRo 27.07.2016 01:03:23
@AlmightyR: просто определите его как метод, который принимает один аргумент. Пример: public bool predefinedQuery(int x) { return x > 7; }. Тогда ваш .Where(predefinedQuery)будет работать нормально.
Don 8.06.2017 20:50:28

List<T>есть FindAllметод, который сделает фильтрацию за вас и вернет подмножество списка.

MSDN имеет отличный пример кода здесь: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

РЕДАКТИРОВАТЬ: Я написал это до того, как у меня было хорошее понимание LINQ и Where()метода. Если бы я написал это сегодня, я бы, вероятно, использовал метод, упомянутый выше Хорхе. FindAllМетод все еще работает , если вы застряли в .NET 2.0 среды , хотя.

12
8.07.2019 09:20:36
Linq хорош, но как минимум на одну величину медленнее, поэтому FindAll и методы расширения фильтрации (например, для массива их несколько), которые не используют IEnumerable, все же имеют смысл для сценариев, где важна производительность. (FWIW, я получил результаты в 7–50 раз больше времени, необходимого Линку и / или IEnumerable, как правило)
Philm 9.05.2017 17:33:05
Есть ли причина, по которой это не принятый ответ? Кажется, что это быстрее, а синтаксис яснее (без вызова toList ()) в конце.
Ran Lottem 10.02.2019 11:07:11

Чтобы сделать это на месте, вы можете использовать метод RemoveAll класса «List <>» вместе с пользовательским классом «Predicate» ... но все, что нужно, это очистить код ... под капотом он делает то же самое что вы ... но да, это делает это на месте, так что вы делаете тот же список временных.

3
25.08.2008 15:15:41

Вы можете использовать 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 при необходимости, а в некоторых случаях, когда вы не используете все элементы в отфильтрованной коллекции, это может обеспечить хороший прирост производительности.

6
25.08.2008 15:22:33

Вы можете использовать метод FindAll в List, предоставляя делегата для фильтрации. Тем не менее, я согласен с @ IainMH, что не стоит слишком волноваться, если это не огромный список.

4
23.05.2017 11:47:13

Если вы используете C # 3.0, вы можете использовать linq

Или, если хотите, используйте специальный синтаксис запроса, предоставляемый компилятором C # 3:

var filteredList = from x in myList
                   where x > 7
                   select x;
3
25.08.2008 15:23:04

Вот блок кода / пример некоторой фильтрации списка с использованием трех различных методов, которые я собрал вместе, чтобы показать фильтрацию списка на основе 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
21
30.12.2013 07:31:39

Использование LINQ относительно медленнее, чем использование предиката, предоставленного FindAllметоду Lists . Также будьте осторожны с LINQ, поскольку перечисление listфактически не выполняется, пока вы не получите доступ к результату. Это может означать, что, когда вы думаете, что создали отфильтрованный список, содержимое может отличаться от того, что вы ожидали, когда фактически читали его.

3
8.07.2019 09:19:15

Если ваш список очень большой и вы фильтруете несколько раз - вы можете отсортировать исходный список по атрибуту фильтра, выполнить бинарный поиск, чтобы найти начальную и конечную точки.

Начальное время O (n * log (n)), затем O (log (n)).

Стандартная фильтрация будет принимать O (n) каждый раз.

1
30.06.2016 11:21:53