Лучший способ проверить содержимое общего списка

Мне нужно поработать над кодом, который использует общие списки для хранения коллекции настраиваемых объектов.

Затем он выполняет что-то вроде следующего, чтобы проверить, есть ли данный объект в коллекции, и если это так, что-то сделать:

List<CustomObject> customObjects;
//fill up the list
List<CustomObject> anotherListofCustomObjects;
//fill it up

//...

foreach (CustomObject myCustomObject in customObjects)
{
   if (anotherListofCustomObjects.Contains(myCustomObject))
   {
      //do stuff
   }
}

Проблема в том, что на обработку 7000 таких объектов уходит вечность.

Это не мой код - я просто пытаюсь придумать варианты его улучшения - Мне кажется, было бы намного быстрее использовать словарь, чтобы получить материал по ключу, вместо того, чтобы перебирать всю коллекцию, как показано выше.

Предложения?

Проблема с перфомансом предполагает, что вам нужно искать альтернативные алгоритмы или структуры данных. Как ты сам сказал.

Christoffer Lette 15.12.2008 17:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
368
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

Ну вроде вы сами ответили? Если вам нужен быстрый запрос к набору данных, тогда словарь может быть лучше, чем плоский список (для больших размеров данных, как у вас).

Вы можете, например, использовать объект как свой собственный ключ -

Dictionary<CustomObject,CustomObject> ...

Обратите внимание, что значение равенства зависит от контекста. Если вы передаете исходную ссылку, то ничего страшного - ContainsKey справится с этой задачей. Если у вас есть объект разные, но похожие для целей равенства для сравнения, тогда вам необходимо реализовать свои собственные GetHashCode(), Equals() и, в идеале, IEquatable<CustomObject>. Либо в самом CustomObject, либо в кастомном IEqualityComparer<CustomObject>.

Использование объекта в качестве ключа к объекту - это ничто иное, как использование самого объекта, чтобы найти себя, как версия списка в исходном сообщении. Ключ словаря должен быть меньшим по размеру и более простым для обработки, чем элемент значения.

Oliver Friedrich 15.12.2008 17:13

@BeowulfOF нет, это не так. Использование объекта в качестве ключа быстрее, потому что вы можете использовать тот же объект (из другого списка), чтобы проверить, есть ли он в словаре.

Frans Bouma 15.12.2008 17:18

@BeowulfOF - это просто ссылка. Конечно, вы может используете отдельный ключ, но это не обязательно. Производительность зависит в первую очередь от сложности Equals и GetHashCode, независимо от того, является ли это ключом объекта или естественным ключом.

Marc Gravell 15.12.2008 17:45

Действительно, ваш код в настоящее время O (n ^ 2), что будет медленным. Ты можешь:

  • используйте словари или KeyedCollections вместо этого, это сделает его O (nlog n)
  • если вы можете гарантировать, что элементы находятся в одном порядке, вы можете переписать последний цикл, чтобы использовать только один индекс, и это будет O (n)

Другой способ, помимо словарей, - если вы используете .NET 3.5, использовать Linq для объектов и Intersect:

foreach(CustomObject c in customObjects.Intersect(anotherListOfCustomObjects))
{
    // do stuff.
}

Согласно рефлектору, он использует наборы на основе хэша для пересечения последовательностей.

Да, это лучше, потому что он выполняет поиск набора в экземплярах Set <T> на основе хэша (который является внутренним классом).

Frans Bouma 15.12.2008 17:14

Производительность от этого не выиграет, даже если это будет медленнее. Linq в основном предназначен только для лучшего понимания, но не для повышения производительности.

Oliver Friedrich 15.12.2008 17:14

@BeowulfOF: вы проверяли код? :) См. Мой предыдущий комментарий. Конечно, если бы «Пересечение» было реализовано с использованием алгоритма O (n * m), как в вопросе, это было бы то же самое, но, к счастью, это не так.

Frans Bouma 15.12.2008 17:16

Кстати, я рассчитал это с помощью простых списков int, и это действительно намного быстрее.

lacop 15.12.2008 20:23

Если вы должен поддерживаете два отдельных списка, один из типов Set может быть быстрее (с использованием операции соединения). Некоторые из доступных библиотек

  1. Коллекции IESI
  2. PowerCollections
  3. C5

Просто незначительное дополнение к другим комментариям. Если вам нужно отсортировать другой список клиентов, вы можете использовать SortedList.

Вы также можете рассмотреть System.Collections.ObjectModel.KeyedCollection<TKey, TItem>.

В дополнение к этому я обычно создаю свой собственный интерфейс IKeyable и конкретную реализацию KeyedCollection, которая использует IKeyable для необходимой перегрузки.

Тесты - твой друг. Размер коллекции определяет структуру данных / алгоритм, который вы должны использовать. Я предлагаю вам провести несколько тестов производительности для следующих опций:

  1. Ваше текущее решение
  2. Используйте алгоритм BinarySearch в отсортированном списке.
  3. Используйте HashSet<CustomObject>.

Учитывая количество элементов, я подозреваю, что HashSet<CustomObject> - это то, что вам нужно.

Хешсет тоже отлично работает.

new HashSet<CustomObject>().Join()

Другие вопросы по теме