Сравнение двух списков через одно свойство с помощью LINQ
Скажем, у меня есть следующее:
class Widget1{
public int TypeID { get; set; }
public string Color { get; set; }
}
class Widget2
{
public int TypeID { get; set; }
public string Brand { get; set; }
}
private void test()
{
List<Widget1> widgets1 = new List<Widget1>();
List<Widget2> widgets2 = new List<Widget2>();
List<Widget1> widgets1_in_widgets2 = new List<Widget1>();
//some code here to populate widgets1 and widgets2
foreach (Widget1 w1 in widgets1)
{
foreach (Widget2 w2 in widgets2)
{
if (w1.TypeID == w2.TypeID)
{
widgets1_in_widgets2.Add(w1);
}
}
}
}
Я использую два цикла foreach для сравнения списков по TypeID для заполнения третьего списка.
Есть ли другой способ использования LINQ для сравнения этих двух списков с помощью TypeID? Возможно, используя Interstect или какую-то другую функцию?
Ответы
Ответ 1
Здесь вы хотите Join
.
var widgets1_in_widgets2 = from first in widgest1
join second in widgets2
on first.TypeID equals second.TypeID
select first;
Intersect
можно более или менее рассматривать как частный случай Join
, где две последовательности имеют один и тот же тип и поэтому могут применяться для равенства вместо необходимости проекции для каждого типа для генерации ключа сравнивать. Учитывая ваш случай, Intersect
не является вариантом.
Если конкретный идентификатор дублируется во втором наборе, и вы не хотите, чтобы элемент был дублирован в результатах, вы можете использовать GroupJoin
вместо Join
:
var widgets1_in_widgets2 = from first in widgest1
join second in widgets2
on first.TypeID equals second.TypeID
into matches
where matches.Any()
select first;
Ответ 2
Вы можете сделать это
widgets2.Where(y=>widget1.Any(z=>z.TypeID==y.TypeID));
Ответ 3
Присоединение имеет недостаток в том, что ваши результаты могут быть дублированы, если widgets1 или widgets2 содержат элементы с одним и тем же идентификатором типа более одного (что также относится к исходному коду, кстати).
Следующее будет делать именно то, что вы хотите: вернуть все элементы из widgets1, для которых в widgets2 существует элемент с соответствующим идентификатором TypeID.
widgets1_in_widgets2 = (from w1 in widgets1
where widgets2.Any(w2 => w1.TypeID == w2.TypeID)
select w1).ToList()
Ответ 4
Попробуйте использовать перегрузку "Где"
var isMatch = !widgets1.Where((w1, index) => w1.TypeId == widgets2[index].TypeId)).Any();
Ответ 5
Мне нравится это решение, потому что его легко читать в коде.
bool result = firstList.All(o => secondList.Any(w => w.Prop1 == o.Prop1 && w.Prop2 == o.Prop2));
Посмотрите полный пример в скрипте: Сравнение примеров скрипта
Ответ 6
widgets2.Where(y=>widget1.Any(z=>z.TypeID==y.TypeID));
Кто-нибудь знает, что за T-QSL он генерирует?