对象的 LINQ 检查列表包含一个值而不是其他一些值

Posted

技术标签:

【中文标题】对象的 LINQ 检查列表包含一个值而不是其他一些值【英文标题】:LINQ check list of objects contain a value AND not some other values 【发布时间】:2022-01-04 14:48:32 【问题描述】:

假设我有这个对象列表:

var shipments = new List<ShipmentTracking>() 
    new ShipmentTracking() 
        trackingNumber = "32021001000", trackings = new List<Tracking>() 
            new Tracking()  trackingCode = "EBC", trackingPoint = "Entered", trackingDateTime = DateTime.Now, trackingMemo = "" 
        
    ,
    new ShipmentTracking() 
        trackingNumber = "32021001001", trackings = new List<Tracking>() 
            new Tracking()  trackingCode = "EBC", trackingPoint = "Entered", trackingDateTime = DateTime.Now.AddDays(1), trackingMemo = "" ,
            new Tracking()  trackingCode = "AWB", trackingPoint = "Registered", trackingDateTime = DateTime.Now.AddDays(1), trackingMemo = "" 
        
    ,
    new ShipmentTracking() 
        trackingNumber = "32021001002", trackings = new List<Tracking>() 
            new Tracking()  trackingCode = "EBC", trackingPoint = "Entered", trackingDateTime = DateTime.Now.AddDays(2), trackingMemo = "" ,
            new Tracking()  trackingCode = "AWB", trackingPoint = "Registered", trackingDateTime = DateTime.Now.AddDays(2), trackingMemo = "" ,
            new Tracking()  trackingCode = "DSP", trackingPoint = "Shipped", trackingDateTime = DateTime.Now.AddDays(2), trackingMemo = "" 
        
    ,
    new ShipmentTracking() 
        trackingNumber = "32021001003", trackings = new List<Tracking>() 
            new Tracking()  trackingCode = "EBC", trackingPoint = "Entered", trackingDateTime = DateTime.Now.AddDays(3), trackingMemo = "" ,
            new Tracking()  trackingCode = "AWB", trackingPoint = "Registered", trackingDateTime = DateTime.Now.AddDays(3), trackingMemo = "" ,
            new Tracking()  trackingCode = "DSP", trackingPoint = "Shipped", trackingDateTime = DateTime.Now.AddDays(3), trackingMemo = "" ,
            new Tracking()  trackingCode = "CCI", trackingPoint = "Cleared", trackingDateTime = DateTime.Now.AddDays(3), trackingMemo = "" 
        
    ,
    new ShipmentTracking() 
        trackingNumber = "32021001004", trackings = new List<Tracking>() 
            new Tracking()  trackingCode = "EBC", trackingPoint = "Entered", trackingDateTime = DateTime.Now.AddDays(4), trackingMemo = "" ,
            new Tracking()  trackingCode = "AWB", trackingPoint = "Registered", trackingDateTime = DateTime.Now.AddDays(4), trackingMemo = "" ,
            new Tracking()  trackingCode = "DSP", trackingPoint = "Shipped", trackingDateTime = DateTime.Now.AddDays(4), trackingMemo = "" ,
            new Tracking()  trackingCode = "CCI", trackingPoint = "Cleared", trackingDateTime = DateTime.Now.AddDays(4), trackingMemo = "" ,
            new Tracking()  trackingCode = "POD", trackingPoint = "Delivered", trackingDateTime = DateTime.Now.AddDays(4), trackingMemo = "" 
        
    
;

我需要只检查并返回具有 trackingCode == "DSP" 但不使用 "CCI" 或 "POD" trackingCode 的货件跟踪的查询,因此在此示例中使用跟踪号 32021001002 进行货件跟踪就是那个。

我试过了,但似乎没有用:

foreach (var shipment in shipments)

    var foo = shipment.trackings.FirstOrDefault((t => t.trackingCode == "DSP" && t.trackingCode != "CCI"));

    if (shipment.trackings.Contains(foo))
    
        
    

感谢任何帮助或指针。 谢谢!

【问题讨论】:

t.trackingCode == "DSP" &amp;&amp; t.trackingCode != "CCI" - 第二个谓词是多余的。如果 TrackingCode 等于“DSP”,则它自动不等于“CCI”。您犯了一个典型的错误,即(作为人类)查看跨行的值,但编写的代码比较同一行中的值 【参考方案1】:

您希望在跟踪列表中发货:有任何跟踪代码“DSP”并且没有任何跟踪代码“CCI”

shipments.Where(s => 
  s.Trackings.Any(t => t.TrackingCode == "DSP") && 
  !s.Trackings.Any(t => t.TrackingCode == "CCI")
);

你也可以这样写:

shipments.Where(s => 
  s.Trackings.Any(t => t.TrackingCode == "DSP") && 
  s.Trackings.All(t => t.TrackingCode != "CCI")
);

有任何跟踪代码是 DSP 且所有跟踪代码都不是 CCI 的货件"

使用对你更有意义的那个

【讨论】:

【参考方案2】:

有 trackingCode == "DSP" 但没有使用 "CCI" 或 “豆荚”

我会填写两个集合以简化它并使其易于更改:

var validCodes = new List<string>"DSP";
var invalidCodes = new List<string>"CCI", "POD";

如果您想忽略大小写,那么将dspDSP 视为您需要StringComparer.OrdinalIgnoreCase,否则StringComparer.Ordinal

查询很简单:

List<ShipmentTracking> trackingList = shipments
    .Where(st => st.trackings.Any(t => validCodes.Contains(t.trackingCode, StringComparer.OrdinalIgnoreCase)))
    .Where(st => !st.trackings.Any(t => invalidCodes.Contains(t.trackingCode, StringComparer.OrdinalIgnoreCase)))
    .ToList();

除了两个Where,您还可以将一个与&amp;&amp; 一起使用。我更喜欢两个,因为它更容易阅读。

【讨论】:

以上是关于对象的 LINQ 检查列表包含一个值而不是其他一些值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Linq where 条件检查字符串列表是不是包含任何字符串

Linq 从一个列表中获取对象,其中其他整数列表包含在第一个列表中

检查一个列表是不是包含另一个列表中的元素

检查对象参数是不是包含字母列表

检查 list<t> 是不是包含任何其他列表

检查 list<t> 是不是包含任何其他列表