Как эффективно отфильтровать объекты из (изначально) большого списка объектов


Мне нужно отфильтровать большой список сложных (20+ свойств) объектов в несколько вложенных списков. Чтобы создать подсписки, у меня есть список спецификаций фильтров. Требования: а) элемент не может быть частью двух подсписков и б) должна быть возможность получить все неразделенные элементы после завершения обработки.

В настоящее время я использую следующий алгоритм:

  1. пункт списка
  2. Поместите объекты для фильтрации в общий список
  3. для каждого фильтра спецификация:
    • Создайте выражение Where (Expression>)
    • примените выражение с помощью Linq > Where к списку объектов
    • получить результирующее IEnumerable выбранных объектов и сохранить их в списке вместе с описанием фильтра
    • удалите найденные элементы из исходного списка с помощью Linq > за исключением создания нового списка для продолжения работы и предотвращения помещения объекта в более чем один подсписок
  4. Проверьте, есть ли есть еще (неразделенные) объекты в рабочем списке

Мой первоначальный список объектов может быть более 400.000 объектов, и я заметил, что как фильтрация, так и сокращение рабочего списка занимает некоторое время. Поэтому я хотел бы знать:

  1. фильтрация для создания вложенных списков происходит максимум по 7 свойствам моего объекта. Есть ли способ, чтобы улучшить производительность в LINQ >, где выбор?
  2. Есть ли способ предотвратить выделение элементов в несколько под-списки, не уменьшая рабочую коллекцию с помощью Except или RemoveAll (возможное улучшение)?

Заранее спасибо!

1 2

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 может быть следующим: сложный, как вам нужно, чтобы он был. Единственное условие состоит в том, что он принимает a T и возвращает a bool. Если этого недостаточно, ничто не мешает вам реализовать свой собственный MyPredicate<???> с любой необходимой вам подписью.

EDIT : отредактировал код для обработки" корзины по умолчанию ", в которую попадают элементы, не соответствующие ни одному из указанных предикатов.