-2

Out of two lists: listA and listB, I want to remove all entries of listB from listA based on some condition.

Now when I try .Except, I am not getting desired result.

// This comes with listA
var usingExcept = listA.Except(listB).ToList(); 

But when I try .RemoveAll then I get desired result.

listA.RemoveAll(x => listB.Exists(y => y.OperationId == x.OperationId));

How to leverage .Except here, if possible?

.Net Fiddle with example.

Code:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var listA = new List<MyObject>{new()
        {OperationId = 123, Mode = "In-Transit", Location = "ATL", }, new()
        {OperationId = 234, Mode = "Delivered", Location = "PHX", }, new()
        {OperationId = 345, Mode = "Delivered", Location = "COL", }};
        
        var listB = new List<MyObject>{new()
        {OperationId = 123, Mode = "In-Transit", Location = "ATL", }};
        
        var usingExcept = listA.Except(listB);
        Console.WriteLine(usingExcept.Count());
        
        listA.RemoveAll(x => listB.Exists(y => y.OperationId == x.OperationId));
        Console.WriteLine(usingExcept.Count());
    }
}

public class MyObject
{
    public int OperationId { get; set; }
    public string Mode { get; set; }
    public string Location { get; set; }
}
GThree
  • 2,708
  • 7
  • 34
  • 67
  • To use `Except` here you will need to implement an [equality comparer](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iequalitycomparer-1?view=net-8.0) for your class – stuartd May 03 '23 at 18:47

1 Answers1

1

You should explain how to compare MyObject instances for equality. For instance:

public class MyObject : IEquitable<MyObject>
{
    public int OperationId { get; set; }
    public string Mode { get; set; }
    public string Location { get; set; }

    public bool Equals(MyObject other) => 
        other is not null && OperationId == other.OperationId;

    public override bool Equals(object o) => Equals(o as MyObject);

    public override int GetHashCode() => OperationId;
}

Then Except will start working as you want (i.e. compare OperationId)

Another possibility is to implement custom equality comparer:

public sealed class MyComparer : IEqualityComparer<MyObject> 
{
    public bool Equals(MyObject left, MyObject right) 
    {
        if (ReferenceEquals(left, right))
            return true;
        if (left is null || right is null)
            return false;

        return left.OperationId == right.OperationId;
    }

    public int GetHashCode(MyObject o) => o is null 
        ? -1
        : o.OperationId;
}

and then provide it when using Except:

var usingExcept = listA.Except(listB, new MyComparer());
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • This is a great example for `IEqualityComparer`. Now I am wondering if I can make this generic or not. So that other class(es) can also use that, if needed. What would be the best approach for that? – GThree May 03 '23 at 19:07