Применить Comparer при выполнении LINQ JOIN

168
17 апреля 2019, 03:40

Можно ли как-нибудь применить особый Comparer при соединении 2-ух последовательностей синтаксисом запросов?

Например, есть 2 листа и я хочу их без учета регистра соединить.

Конечно я могу между equals все привести в верхний регистр, но это не совсем верно.

Можно ли как-то задать метод сравнения явно?

static List<(string, string)> GetDifferent(IEnumerable<string> list1, IEnumerable<string> list2)
{
    var left = from item1 in list1
               join item2 in list2 on item1.ToUpper() equals item2.ToUpper()
                   into temp
               from item2 in temp.DefaultIfEmpty()
               select (item1, item2);
    var right = from item2 in list2
                join item1 in list1 on item2.ToUpper() equals item1.ToUpper()
                    into temp
                from item1 in temp.DefaultIfEmpty()
                select (item1, item2);
    return left.Union(right).Where(x => x.Item1 == null || x.Item2 == null).ToList();
}
Answer 1

В query-syntax для join доступен лишь оператор равенства equals.

Однако, метод Join имеет перегрузку принимающую IEqualityComparer.

Так как в коде left outer join, то следует использовать метод GroupJoin, который также имеет перегрузку принимающую IEqualityComparer.

Например:

IEqualityComparer ec = ...;
var left = list1.GroupJoin(
    list2,
    item1 => item1,
    item2 => item2,
    (item1, items2) => new {item1, items2}
    ec
).SelectMany(
    item => item.items2.DefaultIfEmpty(),
    (item, item2) => (item.item1, item2)
);
Answer 2

В синтаксисе запросов linq в join можно указать только точное соответствие: equals. Но можно вместо него использовать where и там уже использовать компаратор.

Аналогом этого кода:

from item1 in list1
join item2 in list2
on item1.ToUpper() equals item2.ToUpper()
select (item1, item2);

будет следующий:

from item1 in list1
from item2 in list2
where item1.Equals(item2, StringComparison.OrdinalIgnoreCase)
select (item1, item2);

Но я затрудняюсь преобразовать в эту форму код с использованием into.

Для исключения элементов одной последовательности из другой можно (нужно) применять метод Except:

list1.Except(list2, StringComparer.OrdinalIgnoreCase)
list2.Except(list1, StringComparer.OrdinalIgnoreCase)

Соответственно, полный код может выглядеть как-то так:

var left = list1.Except(list2, StringComparer.OrdinalIgnoreCase)
    .Select(item => (item, (string)null));
var right = list2.Except(list1, StringComparer.OrdinalIgnoreCase)
    .Select(item => ((string)null, item));
return left.Union(right).ToList();
READ ALSO
Создать приложение - стукач

Создать приложение - стукач

есть задача от заказчика создать приложение "Стукач", его цель заключается в том чтобы сотрудники работающие на предприятии могли фотографировать...

170
asp net core web api не принимает запросы с клиента multipart

asp net core web api не принимает запросы с клиента multipart

код который работает на сервере

156
WPF анимация тормозит другие окна

WPF анимация тормозит другие окна

Есть основное окно, которое создает немодальное окно через Show(), на котором (немодальном окне) есть ProgressBar с IsIndeterminate="True"

169
Выбор уникальных из List&lt;Dictionary&lt;string, string&gt;&gt;

Выбор уникальных из List<Dictionary<string, string>>

Подскажите как реализовать функцию отбора уникальных в

164