Как сравнить два списка по комбинации двух свойств и выбрать строку, у которой есть несоответствие в третьем свойстве? - PullRequest
0 голосов
/ 29 августа 2018

Я хочу сравнить следующие два списка по комбинации двух свойств (Страна и Город).

При сравнении Индия-Ченнай присутствует в обоих списках и имеет одинаковое значение (1). Точно так же Великобритания-Лондон также присутствует в обоих списках и имеет одинаковое значение (3). Однако, хотя США-Нью-Йорк присутствуют в обоих списках, их значения не совпадают (2 в списке 1 и 5 в списке 2).

Пожалуйста, помогите мне написать кратчайшее возможное выражение linq, чтобы выбрать только '2-USA-New York' из списка1, поскольку его значение не совпадает с list2 ('5-USA-New York').

void Main()
{
    List<A> list1 = new List<A> {
        new A { Country = "India", City = "Chennai", Value = 1 },
        new A { Country = "USA", City = "New York", Value = 2 },
        new A { Country = "UK", City = "London", Value = 3 }
    };

    List<A> list2 = new List<A> {
        new A { Country = "India", City = "Chennai", Value = 1 },
        new A { Country = "USA", City = "New York", Value = 5 },
        new A { Country = "UK", City = "London", Value = 3 }
    };

    list1.Dump();
    list2.Dump();
}

class A
{
    public int Value { get; set; }
    public string Country { get; set; }
    public string City { get; set; }
}

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Я понимаю, что на этот вопрос уже был получен удовлетворительный ответ, но вот альтернативное решение.

Это может быть немного более интуитивно понятным / простым для некоторых, поскольку он избегает всей концепции join и просто ищет любую строку, соответствующую текущей строке .

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

var result = list1
              .Where(rowFromFirst => 
                       list2.Any(rowFromSecond => 
                                    rowFromSecond.Country == rowFromFirst.Country &&
                                    rowFromSecond.City == rowFromFirst.City && 
                                    rowFromSecond.Value != rowFromFirst.Value));
0 голосов
/ 29 августа 2018

Предполагается, что в ваших списках нет дублирующихся пар { Country, City }:

var list1Missmatched = list1
    .Join(list2, 
          left => new { left.Country, left.City },
          right => new { right.Country, right.City }, 
          (left, right) => new { left, right })
    .Where(x => x.left.Value != x.right.Value)
    .Select(x => x.left)
    .ToList();

Это работает, потому что в leftList.Join(rightList, leftMatchBy, rightMatchBy, matchedPairResultSelector) мы используем «анонимный объект» в качестве ключа для сопоставления. Равенство (и хэш-код) анонимных объектов ведет себя так же, как и для типа значения, то есть new { Foo = 1 } и new { Foo = 1 } равны и имеют одинаковый хеш-код, даже если они являются двумя разными экземплярами.

Join создает хэш-таблицу из пар (matchByKey, listItem), что обеспечивает почти линейную алгоритмическую сложность - O (n) (в отличие от решения Where(Any()), имеющего квадратичную сложность - O ( п ^ 2)). Если вам интересно, недавно я написал небольшой тест производительности , сравнивающий эти два подхода.

...