Как объединить две коллекции c
Перейти к содержимому

Как объединить две коллекции c

  • автор:

Операции Distinct, Union, Except и Intersect

Операции множеств используются для выполнения математических операций с множествами на последовательностях.

Distinct

Операция Distinct удаляет дублированные элементы из входной последовательности. У операции Distinct есть один прототип, описанный ниже:

Эта операция возвращает объект, перечисляющий элементы входной последовательности source и выдающий последовательность, в которой каждый элемент не эквивалентен предыдущим выданным. Эквивалентность элементов определяется методами GetHashCode и Equals.

Давайте рассмотрим пример использования операции Distinct:

Использование LINQ-операции Distinct

Union

Операция Union возвращает объединение множеств из двух исходных последовательностей. У этой операции имеется один прототип, описанный ниже:

Эта операция возвращает объект, который сначала перечисляет элементы последовательности по имени first, выдавая последовательность, в которой каждый элемент не эквивалентен предыдущим выданным, затем перечисляет вторую входную последовательность second, опять-таки, выдавая последовательность без повторений. Эквивалентность элементов определяется методами GetHashCode и Equals.

Чтобы продемонстрировать разницу между операцией Union и описанной ранее операцией Concat, в примере, представленном ниже, создаются последовательности first и second из массива cars, что приведет к дублированию пятого элемента в обеих последовательностях. Затем отображается количество элементов в массиве cars, а также в последовательностях first и second, наряду с количеством элементов в конкатенированной и объединенной последовательностях:

В конечном итоге последовательность concat должна иметь на один элемент больше, чем массив cars. Последовательность union должна содержать то же количество элементов, что и массив cars. Это доказывают результаты выполнения кода:

Пример вызова LINQ-операции Union

Intersect

Операция Intersect возвращает пересечение множеств из двух исходных последовательностей. Операция Intersect имеет один прототип, описанный ниже:

Эта операция возвращает объект, который сначала перечисляет элементы последовательности по имени first, выбирая оттуда каждый элемент, который не эквивалентен предыдущему выбранному элементу. Затем он перечисляет вторую входную последовательность, помечая любой элемент, имеющийся в обеих последовательностях, для включения в выходную последовательность. Затем осуществляется проход по помеченным элементам, с помещением их в выходную последовательность в том порядке, в котором они были собраны. Эквивалентность элементов определяется с помощью методов GetHashCode и Equals.

Чтобы продемонстрировать применение операции Intersect, ниже используются операции Take и Skip для генерации двух последовательностей и получения некоторого их перекрытия, как в примере с Union, где был намеренно дублирован пятый элемент. После вызова операции Intersect на этих двух сгенерированных последовательностях в возвращаемой последовательности intersect должен оказаться только дублированный пятый элемент:

В конечном итоге должна быть получена последовательность auto, которая состоит только из одного элемента, содержащего дублированный пятый элемент массива cars — Chevrolet:

Пример использования операции Intersect

Итак, LINQ работает! Насколько часто вам приходилось ранее выполнять операции над множествами элементов из двух коллекций? Было ли это трудно? Благодаря LINQ, все сложности в прошлом.

Except

Операция Except возвращает последовательность, содержащую все элементы первой последовательности, которых нет во второй последовательности. Эта операция имеет один прототип, описанный ниже:

Эта операция возвращает объект, который при перечислении перебирает элементы входной последовательности по имени second, собирая все элементы, которые не эквивалентны ранее собранным. Затем происходит перечисление входной последовательности first, с выдачей каждого ее элемента, которого нет в коллекции из второй последовательности. Эквивалентность одного элемента другому определяется с использованием их методов GetHashCode и Equals.

В следующем примере используются два массива arr1 и arr2. С помощью операции Except будут удалены взаимоисключающие элементы коллекций:

Как объединить две коллекции c

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

Разность последовательностей

С помощью метода Except() можно получить разность двух последовательностей:

В данном случае из массива soft убираются все элементы, которые есть в массиве hard . Результатом операции будут два элемента:

Пересечение последовательностей

Для получения пересечения последовательностей, то есть общих для обоих наборов элементов, применяется метод Intersect :

Так как оба набора имеют только один общий элемент, то соответственно только он и попадет в результирующую выборку:

Удаление дубликатов

Для удаления дублей в наборе используется метод Distinct :

Объединение последовательностей

Для объединения двух последовательностей используется метод Union . Его результатом является новый набор, в котором имеются элементы, как из первой, так и из второй последовательности. Повторяющиеся элементы добавляются в результат только один раз:

Результатом операции будет следующий набор:

Если же нам нужно простое объединение двух наборов, то мы можем использовать метод Concat :

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

Последовательное применение методов Concat и Distinct будет подобно действию метода Union.

Работа со сложными объектами

Для сравнения объектов в последовательностях применяются реализации методов GetHeshCode() и Equals(). Поэтому если мы хотим работать с последовательностями, которые содержат объекты своих классов и структур, то нам необходимо определить для них подобные методы:

Здесь объекты Person сравниваются исходя из значения их свойства Name — если имена равны, то и объекты Person равны. Консольный вывод:

Joining two lists together

If I have two lists of type string (or any other type), what is a quick way of joining the two lists?

The order should stay the same. Duplicates should be removed (though every item in both links are unique). I didn’t find much on this when googling and didn’t want to implement any .NET interfaces for speed of delivery.

Peter Mortensen's user avatar

GurdeepS's user avatar

15 Answers 15

This preserves the order of the lists, but it doesn’t remove any duplicates (which Union would do).

This does change list a . If you wanted to preserve the original lists then you should use Concat (as pointed out in the other answers):

This returns an IEnumerable as long as a is not null.

John Smith's user avatar

ChrisF's user avatar

The way with the least space overhead is to use the Concat extension method.

It creates an instance of IEnumerable<T> which will enumerate the elements of list1 and list2 in that order.

The Union method might address your needs. You didn’t specify whether order or duplicates was important.

Take two IEnumerables and perform a union as seen here:

Something like this:

Or, you can use the ‘Union’ extension method that is defined in System.Linq. With ‘Union’, you can also specify a comparer, which can be used to specify whether an item should be unioned or not.

Vivek Jain's user avatar

It’s working fine I think so. As previously said, Concat returns a new sequence and while converting the result to List, it does the job perfectly. Implicit conversions may fail sometimes when using the AddRange method.

Peter Mortensen's user avatar

If some item(s) exist in both lists you may use

jimpanzer's user avatar

As long as they are of the same type, it’s very simple with AddRange:

hichris123's user avatar

David's user avatar

Vivek Jain's user avatar

Krishan's user avatar

one way: List.AddRange() depending on the types?

Prasad Telkikar's user avatar

One way, I haven’t seen mentioned that can be a bit more robust, particularly if you wanted to alter each element in some way (e.g. you wanted to .Trim() all of the elements.

//Get the products from the both arrays //excluding duplicates.

Miroslav Siska's user avatar

The two options I use are:

However I noticed as I used that when using the AddRange method with a recursive function, that calls itself very often I got an SystemOutOfMemoryException because the maximum number of dimensions was reached.

(Message Google Translated)
The array dimensions exceeded the supported range.

LINQ в C#: объединение коллекций

Кроме фильтрации, выбора и группировки последовательностей в LINQ C# также предусмотрен ряд методов, позволяющих объединять как однородные, так и разнородные (содержащие элементы различных типов данных) коллекции.

Метод Concat

Метод Concat объединяет две однородные коллекции. Например,

Метод Join

Позволяет объединить две разнородные коллекции по определенному признаку (ключу). Например, у нас уже есть класс, содержащий данные каких-то измерений:

Данные о том, кто именно проводил эти измерения содержатся в другом классе:

Коллекции будут выглядеть следующим образом:

Ключом, т.е. признаком по которому мы будем объединять две коллекции с помощью метода LINQ Join может выступать название измерения, то есть — это поле Name у класса DataObject и поле MeasurementName у класса Measurement . Объединим две коллекции следующим образом:

Метод Zip

Объединяет две коллекции последовательно в соответствии с их индексами, то есть первый элемент первой коллекции соединяется с первым элементов второй коллекции, второй элемент первой коллекции — со вторым элементов второй коллекции и так далее.

Метод Zip не проводит никаких проверок на равенство ключей, а просто «механически» соединяет две разнородные коллекции. Результат:

Итого

Сегодня мы рассмотрели три метода объединения коллекций в LINQ C#: Concat — объединяет две однородные коллекции, Zip — объединяет две разнородные коллекции, Join — объединяет две разнородные коллекции по ключу.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *