Найти дубликаты в нескольких списках с помощью linq

1

У меня есть 4 класса, каждый из которых наследуется от одного и того же базового класса. Все они имеют свойство Id & Path. Когда мои данные загружаются из xml, я строю 4 списка на основе этих классов.

У меня есть следующий код, который позволяет мне сравнить 2 списка:

var list1 = settings.EmailFolders.Select(m => m.Path).ToList().
Intersect(settings.LogPaths.Select(m=>m.Path).ToList()).ToList();

но я бы хотел

  1. Я хочу сравнить 1-й список с другими 3 и найти, если существует дублированный путь.

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

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

Обратите внимание, что я не хочу, чтобы точки 1, 2 и 3 выполнялись в одном процессе, так как я хотел бы сообщить о соответствующей ошибке, если будут найдены дубликаты.

Если я повторно использую вышеуказанное и добавлю дополнительный Intersect с дополнительным списком,

var list1 = settings.EmailFolders.Select(m => m.Path).ToList().
Intersect(settings.LogPaths.Select(m=>m.Path).ToList()).
Intersect(settings.SuccessPaths.Select(m=>m.Path).ToList()).
Intersect(settings.FailurePaths.Select(m=>m.Path).ToList()).List();

Вышеизложенное хотелось бы применить оператор a and operator между каждым, а не оператором or оператором, который не является тем, что я хочу. Мне нужно знать, если какой-либо из путей, используемых в FailurePaths или LogPaths или SuccessPaths, уже используется в моем почтовом ящике EmailFolder.Path

ОБНОВИТЬ:

Я обновил свой вопрос с ответом на основе предложения @Devuxer, который является правильным ответом, но вместо того, чтобы работать со строковым массивом, я основываю его на списке классов, все из которых содержат свойство Path.

List<EmailFolder> emailFolders = LoadEmailFolders();
List<LogPath> logPaths = LoadLogPaths();
List<SuccessPath> successPaths = LoadSuccessPaths();
List<FailurePath> failurePaths = LoadFailurePaths();

var pathCollisions = EmailFolders.Select(a=>a.Path)
.Intersect(LogPaths.Select(b=>b.Path))
.Select(x => new { Type = "LogPath", Path = x })
.Concat(EmailFolders.Select(c=>c.Path)
.Intersect(SuccessPaths.Select(d=>d.Path))
.Select(x => new { Type = "SuccessPath", Path = x }))
.Concat(EmailFolders.Select(e=>e.Path)
.Intersect(FailurePaths.Select(f=>f.Path))
.Select(x => new { Type = "FailurePath", Path = x })).ToList();

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

Теги:
linq

2 ответа

0
Лучший ответ

Возможно, я немного недооцениваю ваши требования, но похоже, что вы хотите что-то вроде этого:

var emailFolders = new[] { "a", "b", "c" };
var logPaths = new[] { "c", "d", "e" };
var successPaths = new[] { "f", "g", "h" };
var failurePaths = new[] { "a", "c", "h" };

var pathCollisions = emailFolders
    .Intersect(logPaths)
    .Select(x => new { Type = "Email-Log", Path = x })
    .Concat(emailFolders
        .Intersect(successPaths)
        .Select(x => new { Type = "Email-Success", Path = x }))
    .Concat(emailFolders
        .Intersect(failurePaths)
        .Select(x => new { Type = "Email-Failure", Path = x }));

Это приводит к:

Type          | Path
--------------------
Email-Log     |  c 
Email-Failure |  a 
Email-Failure |  c
--------------------

Если это то, что вы искали, Intersect определенно был правильным способом найти дубликаты. Я просто добавил некоторые предложения Concat и предоставил Type чтобы вы могли видеть, какой тип столкновения пути произошел.

редактировать

Ну, пули в вашем вопросе, похоже, просят что-то отличное от последнего предложения вашего вопроса.

Если вы действительно хотите все сравнения, один из способов сделать это - добавить дополнительные предложения Concat:

var pathCollisions = emailFolders
    .Intersect(logPaths)
    .Select(x => new { Type = "Email-Log", Path = x })
    .Concat(emailFolders
        .Intersect(successPaths)
        .Select(x => new { Type = "Email-Success", Path = x }))
    .Concat(emailFolders
        .Intersect(failurePaths)
        .Select(x => new { Type = "Email-Failure", Path = x }))
    .Concat(logPaths
        .Intersect(successPaths)
        .Select(x => new { Type = "Log-Success", Path = x }))
    .Concat(logPaths
        .Intersect(failurePaths)
        .Select(x => new { Type = "Log-Failure", Path = x }))
    .Concat(successPaths
        .Intersect(failurePaths)
        .Select(x => new { Type = "Success-Failure", Path = x }));

Тем не менее, это не "короткое замыкание", как вы предполагали (так что он найдет все конфликты пути, а не остановится после первого типа), но он должен по крайней мере предоставить вам данные, необходимые для создания отчета.

  • 0
    Я должен попробовать то, что вы предложили. Это заставило меня улыбнуться :) с удивлением, что можно сделать в linq и как мало я до сих пор не знаю об этом предмете. Поистине удивительно! То, что у вас есть, выглядит хорошо, но вместо того, чтобы применять массивы строк, я хочу применить это к списку объектов.
  • 0
    @ Thierry, чтобы мой пример работал для вашей ситуации, я думаю, что вы можете просто сделать new { Type = "Email-Log", Path = x.Path } для каждого new оператора.
Показать ещё 1 комментарий
0

Вы можете использовать Содержит, используя свойство для сравнения

 var result = list1.Where(x => list2.Contains(x.Path));

Он предоставит все элементы из списка1, которые также находятся в списке2

Если вы хотите только подсчет, используйте.Count() в конце

То же правило применяется для сравнения других 3 списков

Ещё вопросы

Сообщество Overcoder
Наверх
Меню