Как эффективно отфильтровать объекты из (изначально) большого списка объектов
Мне нужно отфильтровать большой список сложных (20+ свойств) объектов в несколько вложенных списков. Чтобы создать подсписки, у меня есть список спецификаций фильтров. Требования: а) элемент не может быть частью двух подсписков и б) должна быть возможность получить все неразделенные элементы после завершения обработки.
В настоящее время я использую следующий алгоритм:
- пункт списка
- Поместите объекты для фильтрации в общий список
- для каждого фильтра спецификация:
- Создайте выражение Where (Expression>)
- примените выражение с помощью Linq > Where к списку объектов
- получить результирующее IEnumerable выбранных объектов и сохранить их в списке вместе с описанием фильтра
- удалите найденные элементы из исходного списка с помощью Linq > за исключением создания нового списка для продолжения работы и предотвращения помещения объекта в более чем один подсписок
- Проверьте, есть ли есть еще (неразделенные) объекты в рабочем списке
Мой первоначальный список объектов может быть более 400.000 объектов, и я заметил, что как фильтрация, так и сокращение рабочего списка занимает некоторое время. Поэтому я хотел бы знать:
- фильтрация для создания вложенных списков происходит максимум по 7 свойствам моего объекта. Есть ли способ, чтобы улучшить производительность в LINQ >, где выбор?
- Есть ли способ предотвратить выделение элементов в несколько под-списки, не уменьшая рабочую коллекцию с помощью Except или RemoveAll (возможное улучшение)?
Заранее спасибо!
1 ответ:
Если вы не можете использовать какие-либо индексы в входящем списке, который вы пытаетесь классифицировать, то вам лучше просто повторить весь список только один раз и классифицировать элементы по ходу. Таким образом, вы избегаете ненужных операций remove и , за исключением операций, которые серьезно вредят производительности с помощью бессмысленных итераций и сравнений равенства.
Я думал о чем-то длинной строчке:
public static IDictionary<string, List<T>> Classify<T>(this IEnumerable<T> items, IDictionary<string, Predicate<T>> predicates, out List<T> defaultBucket) { var classifiedItems = new Dictionary<string, List<T>>(predicates.Count); defaultBucket = new List<T>(); foreach (var predicate in predicates) { classifiedItems.Add(predicate.Key, new List<T>()); } foreach (var item in items) { var matched = false; foreach (var predicate in predicates) { if (predicate.Value(item)) { matched = true; classifiedItems[predicate.Key].Add(item); break; } } if (!matched) { defaultBucket.Add(item); } } return classifiedItems; }
Любое данное
predicate
может быть следующим: сложный, как вам нужно, чтобы он был. Единственное условие состоит в том, что он принимает aT
и возвращает abool
. Если этого недостаточно, ничто не мешает вам реализовать свой собственныйMyPredicate<???>
с любой необходимой вам подписью.EDIT : отредактировал код для обработки" корзины по умолчанию ", в которую попадают элементы, не соответствующие ни одному из указанных предикатов.