Я ищу очень быстрый способ отфильтровать коллекцию на C #. В настоящее время я использую общие коллекции List <object>, но я открыт для использования других структур, если они работают лучше.
В настоящее время я просто создаю новый List <object> и перебираю исходный список. Если критерии фильтрации совпадают, я помещаю копию в новый список.
Есть лучший способ сделать это? Есть ли способ выполнить фильтрацию, чтобы временный список не требовался?
c#
collections
filtering
Джейсон Зи
источник
источник
Ответы:
Если вы используете 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;
в верхней части файла.источник
.Where(predefinedQuery)
вместо использования.Where(x => x > 7)
?public bool predefinedQuery(int x) { return x > 7; }
. Тогда ваш.Where(predefinedQuery)
будет работать нормально.Вот блок кода / пример некоторой фильтрации списка с использованием трех разных методов, которые я собрал вместе, чтобы показать фильтрацию списков на основе 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
источник
List<T>
естьFindAll
метод, который будет выполнять фильтрацию за вас и возвращать подмножество списка.У MSDN есть отличный пример кода: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx
РЕДАКТИРОВАТЬ: Я написал это до того, как хорошо разбирался в LINQ и
Where()
методе. Если бы я написал это сегодня, я бы, вероятно, использовал метод, упомянутый Хорхе выше. Однако этотFindAll
метод все еще работает, если вы застряли в среде .NET 2.0.источник
Вы можете использовать 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, когда это необходимо, и в некоторых случаях, когда вы не используете все элементы в отфильтрованной коллекции, это может обеспечить хороший прирост производительности.
источник
Чтобы сделать это на месте, вы можете использовать метод RemoveAll класса «List <>» вместе с настраиваемым классом «Predicate» ... но все, что он делает, это очищает код ... под капотом он делает то же самое то, что вы ... но да, он делает это на месте, поэтому вы делаете то же самое, что и временный список.
источник
Вы можете использовать метод FindAll списка, предоставляя делегата для фильтрации. Хотя я согласен с @ IainMH, что не стоит слишком сильно беспокоиться, если только это не огромный список.
источник
Или, если хотите, используйте специальный синтаксис запроса, предоставляемый компилятором C # 3:
var filteredList = from x in myList where x > 7 select x;
источник
Использование LINQ относительно намного медленнее, чем использование предиката, предоставленного
FindAll
методу Lists . Также будьте осторожны с LINQ, поскольку перечислениеlist
фактически не выполняется, пока вы не получите доступ к результату. Это может означать, что, когда вы думаете, что создали отфильтрованный список, содержимое может отличаться от того, что вы ожидали, когда на самом деле читали его.источник
Если ваш список очень большой, и вы постоянно фильтруете - вы можете отсортировать исходный список по атрибуту фильтра, используя двоичный поиск, чтобы найти начальную и конечную точки.
Начальное время O (n * log (n)), затем O (log (n)).
Стандартная фильтрация будет занимать O (n) каждый раз.
источник