LINQ 查询,用于在与泛型列表不同的列表之间进行选择

本文关键字:列表 之间 选择 行选 LINQ 用于 泛型 查询 | 更新日期: 2023-09-27 17:50:13

我有两个通用列表,我想在其中运行几个 Linq 查询来找出:

  1. 列表 A 中的任何项目是否在列表 B 中找到

  2. 列表 A 中的所有项目都在列表 B 中找到吗

以下是列表:

var ListA = new List<long>()
var ListB = new List<MyObject>()

MyObject 定义为:

public class MyObject
  {
    public long ItemId { get; set; }    
    // ... Other stuff...
  }

我试图确定两件事(两个查询(:1.ListA中的任何长头是否与ListB中的任何MyObject.ItemId匹配? 和 2. 列表 A 中的所有多头都可以在列表 B 中找到吗?

列表 A 和列表 B 可以是不同的长度。 对于数字 2,我需要在 ListB 中找到的所有 ListA 项目,反之亦然。 我希望这是有道理的。

谢谢

-斯科特

LINQ 查询,用于在与泛型列表不同的列表之间进行选择

首先,你只关心 ListB 中的 ItemId,所以:

var bIDs = ListB.Select(x => x.ItemId);

为了回答您问题的第一部分,我将通过找到两个列表(它们共享的所有项目的集合(的交集来解决这个问题。如果它至少包含一个元素,则两者之间存在重叠。

var sharedIds = ListA.Intersect(bIDs);
if (sharedIds.Any())
    // list A contains at least one ItemID which ListB contains

至于第二部分,你想看看列表A是否是列表B的子集。

if (!ListA.Except(bIDs).Any())
    // yes, list A is a subset of list B

此代码段之所以有效,是因为ListA.Except(bIDs)可以找到ListA具有而bIDs没有的元素。如果这是空的,则ListA不包含bIDs不包含的任何内容。因此,ListA中的所有内容也在bIDs .

下面是一个例子:A = {1, 2} ; B = {1, 2, 3} .A 是 B 的子集。 A.Except(B) 给你一个空集 - B 同时有 1 和 2,所以不能在结果列表中,B 中没有任何东西。因此,当 A 是 B 的子集时,A.Except(B).Any()给出 false,因为结果中没有元素;因此,如果我们想处理这种情况,我们显然会否定它。

为了完整起见,如果我们交换 A 和 B 轮,使得 A 不是 B 的子集:A = {1, 2, 3} ; B = {1, 2},那么A.Except(B)就给{3}。它不能包含 1 或 2,因为 B 包含 1 和 2。但是 B 不包含 3,所以 A.Except(B) 可以包含它。由于{3}包含一个元素,因此它不为空,因此A.Except(B).Any()为真。否定,如果 A 不是 B 的子集,则为假。

我的解释有点简洁;如果你想进一步查找(我建议你这样做 - 一点集合论可以走很长的路(,A.Except(B) LINQ 对集合差或相对集合补码的名称。维基教科书对集合论有一个不错的介绍,如果你有这样的倾向。

var value1 =
(
    from itemA in ListA
    where ListB.Any(itemB => itemB.ItemID == itemA)
    select item
).Count();
var value2 = value1 == ListA.Count();

为了测试条件,假设您将ItemIds列表提取到listB中:

bool inListA = listA.Any(x => listB.Contains(x));
bool allInListB = listA.All(x => listB.Contains(x));

就地测试而不提取单独的列表(如果ItemIds(

bool inListA = listA.Any(x => listB.Select(b => b.ItemId).Contains(x));
bool allInListB = listA.All(x => listB.Select(b => b.ItemId).Contains(x));

如果需要同时回答所有三个问题,则纯 LINQ 解决方案可能不是最佳的,因为各个查询都需要执行相同的交集操作。做一次交集,然后使用该结果回答你的三个问题:

var tempSet = new HashSet<long>(ListA);
int uniqueAItemCount = tempSet.Count;
// 2b. "I would need all of ListA's items found in ListB, but not vice-versa."
tempSet.IntersectWith(ListB.Select(x => x.ItemId));
// tempSet now contains all items from ListA also found in ListB
// we can use this result to answer the other two questions...
// 1. "Do any of the longs in ListA match any of the MyObject.ItemId in ListB?"
bool anyAFoundInB = tempSet.Count > 0;
// 2a. "Can all of the longs in ListA be found in ListB?"
bool allAFoundInB = tempSet.Count == uniqueAItemCount;