【问题标题】:LINQ Query To Select Between Unlike Generic Lists在不同的通用列表之间进行选择的 LINQ 查询
【发布时间】:2011-04-13 22:30:23
【问题描述】:

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

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

  2. 是否在列表 B 中找到了列表 A 的所有项目

以下是列表:

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

MyObject 定义为:

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

我试图确定两件事(两个查询): 1. ListA 中的任何 long 是否与 ListB 中的任何 MyObject.ItemId 匹配?以及 2. ListA 中的所有 long 都可以在 ListB 中找到吗?

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

谢谢,

-斯科特

【问题讨论】:

  • 我对第 2 部分有点困惑。您想知道 ListA 中的所有项目是否都包含在 B 的 ItemId 中,还是想要 ListA 值的 List 包含在 ItemId 的 List 中B. 略有不同的查询。你的最后一句话让我感到困惑。
  • 我希望 ListA 中的每个 long 至少等于 ListB 中的一个 MyObject.ItemId。

标签: c# linq


【解决方案1】:

首先,你只关心 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 的子集。搜索此内容时,Stack Overflow 显示clean solution

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

这个 sn-p 有效,因为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() 给出错误,因为结果中没有元素;所以如果我们想处理这种情况,我们显然会否定它。

为了完整性,如果我们交换 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 的集合差异或相对集合补充的名称。如果您愿意,Wikibooks 有一个不错的 introduction 来设定理论。

【讨论】:

  • @flesh:使用ifs 等,有点冗长;您认为有什么特别的地方可以简化吗?
  • 如果我错了,请纠正我,但我认为需要删除 NOT 运算符才能使您的最后一个代码示例正常工作。我认为这正是我正在寻找的。谢谢!
  • @Scott:我在那里做了一点解释;我现在无法测试任何 C#,但我认为它是正确的。如果没有,请随意将我放入股票并向我扔虚拟蔬菜。 ;)
  • 复杂?它看起来很简单!很好的答案!
【解决方案2】:
var value1 =
(
    from itemA in ListA
    where ListB.Any(itemB => itemB.ItemID == itemA)
    select item
).Count();

var value2 = value1 == ListA.Count();

【讨论】:

    【解决方案3】:

    仅测试条件,假设您将ItemIds 的列表提取到listB

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

    ItemIdsItemIds 时无需提取单独的列表即可进行测试

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

    【讨论】:

      【解决方案4】:

      如果您需要同时回答所有三个问题,那么纯 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;
      

      【讨论】:

        猜你喜欢
        • 2013-05-02
        • 1970-01-01
        • 2015-05-16
        • 2021-12-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-07
        相关资源
        最近更新 更多