0

Let's say I have this list of objects:

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 = "" }
 }
 }
};

I need the query that would check and return only shipment tracking(s) that has trackingCode == "DSP" but not shipment tracking with "CCI" or "POD" trackingCode, so in this example shipment tracking with tracking number 32021001002 would be the one.

I have tried this but doesn't seem to work:

foreach (var shipment in shipments)
{
 var foo = shipment.trackings.FirstOrDefault((t => t.trackingCode == "DSP" && t.trackingCode != "CCI"));
 if (shipment.trackings.Contains(foo))
 {
 
 }
}

Any help or pointer is appreciated. Thanks!

asked Nov 26, 2021 at 14:41
1
  • 3
    t.trackingCode == "DSP" && t.trackingCode != "CCI" - the second predicate is redundant. if TrackingCode equals "DSP" it is automatically not equal to "CCI". You're making a classic mistake of looking (as a human) at values across rows, but writing code that compares values within the same row Commented Nov 26, 2021 at 14:46

2 Answers 2

2

You want shipments where for the list of trackings: there IS any tracking code "DSP" and there IS NOT any tracking code "CCI"

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

You could also write this as:

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

i.e. shipments where there is any tracking code that is DSP, and all the tracking codes are not CCI"

Use whichever makes more sense to you

answered Nov 26, 2021 at 14:50
1

has trackingCode == "DSP" but not shipment tracking with "CCI" or "POD"

I would fill two collections to simplify it and to make it easy to be changed:

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

If you want to ignore the case, so treat dsp and DSP same you need StringComparer.OrdinalIgnoreCase, otherwise StringComparer.Ordinal.

The query is pretty simple:

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();

Instead of two Where you can also use one with &&. I prefer two because it's easier to read.

answered Nov 26, 2021 at 15:36
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.