var added = New.Except(Source);
var removed = Source.Except(New);
var notModified = Source.Intersect(New);
Если вы хотите использовать подход, в котором вы «показываете свою работу», я бы предложил поместить их каждый в HashSets, поскольку это позволяет провести быструю проверку Contains
по сравнению с другими перечислениями.
Edit:
Хорошо, если мы идем на общую скорость за счет эффективности выражения, то со следующими допущениями:
- У нас есть достаточно хеш-тип элемента (если нет, но он может быть абсолютно отсортирован, тогда SortedList может превзойти хеш-набор).
- Мы не можем предсказать, будет ли Source или New больше (в этом примере есть небольшое преимущество, если я сделаю это наоборот, как у меня, но я предполагаю, что это случайно в данных и что мы должны ожидать каждого с равной вероятностью.
Тогда я бы предложил:
HashSet<T> removed = Source as HashSet<T> ?? new HashSet<T>(Source);
LinkedList<T> added = new LinkedList<T>();
LinkedList<T> notModified = new LinkedList<T>();
foreach(T item in New)
if(removed.Remove(item))
notModified.AddLast(item);
else
added.AddLast(item);
При настройке removed
я проверяю, является ли это уже хэш-набором, чтобы избежать расточительного построения нового (я предполагаю, что ввод вводится как IEnumerable<T>
). Конечно, это разрушительное действие, поэтому мы все равно можем его избежать.
Обратите внимание, что я изменяю хэш-набор при перечислении через него. Это разрешено hashset, но вне гарантий, предоставляемых перечислителями, поэтому зависит от реализации. Тем не менее, с нынешними рамками вкл. это более эффективно, чем тестировать и добавлять в другую удаленную коллекцию.
Я выбрал связанные списки для двух других коллекций, так как они, как правило, хорошо подходят с точки зрения стоимости вставки (не только O (1), но и быстрого O (1) по сравнению с использованием другого набора).
Теперь, если вы хотите пойти еще дальше, возможно, для реализации хэш-набора доступны микрооптимизации, если вы выберете свой собственный.