Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do a custom compare for every item in a intersect of two collections

Tags:

c#

linq

If I have:

IEnumerable<CrewBase> crewBasesLeft;
IEnumerable<CrewBase> crewBasesRight;

and do:

IEnumerable<CrewBase> intersect = crewBasesLeft
.Intersect( crewBasesRight,CrewBaseComparer.OnId() );

How do I get:

CrewBase left;
CrewBase right;

from the:

intersect

so I can loop over all the CrewBases in the Intersect and make a call:

Action(left,right);

I only want to do this on CrewBases that are equal in both list according to my CrewBaseComparer.OnId that implements:

IEqualityComparer<CrewBase>

This is my current implementation:

    IEnumerable<ObjectDifference> GetCrewBaseDifferences2( TrafficPlan left, TrafficPlan right )
    {
        var result = new List<ObjectDifference>();

        IEnumerable<CrewBase> intersect = left.CrewBases.Intersect( right.CrewBases,CrewBaseComparer.OnId() );

        foreach( CrewBase crewBase in intersect )
        {
            CrewBase other = crewBase;
            ObjectDifference diff = crewBase.GetDifference( right.CrewBases.First(x => x.Equals(other, CrewBaseComparer.OnId())) );
            if( diff.HasDifferences )
            {
                result.Add( diff );
            }
        }

        return result;
    }
like image 464
Hakan Forss Avatar asked Dec 30 '25 08:12

Hakan Forss


2 Answers

You'd have to define a class that implements IEqualityComparer:

class CustomComparer : IEqualityComparer<CrewBase>
{
    #region IEqualityComparer<CrewBase> Members

    public bool Equals(CrewBase x, CrewBase y)
    {
        return CustomCompare(x, y);
    }

    public int GetHashCode(CrewBase obj)
    {
        //a hash code based on the specific comparison
    }

    #endregion
}

and then call Intersect with an instance of your class:

IEnumerable<CrewBase> intersect = crewBasesLeft.Intersect(crewBasesRight, new CustomComparer());

It's not necessarily the case that Intersect will always pass an element from "left" and an element from "right" as parameters "x" and "y" respectively, but it's not clear from your question if that matters.

Based on your update, it looks like you need to do a Join instead:

IEnumerable<CrewBase> crewBasesLeft;
IEnumerable<CrewBase> crewBasesRight;

var Join = crewBasesLeft.Join(crewBasesRight, left => left, right => right, (left, right) => new { left, right }, CrewBaseComparer.OnId());

foreach (var i in Join)
{
    Action(i.left, i.right);
}

In this join, we treat each element as the key and use your existing custom IEqualityComparer to compare the instances. The result selector for the join returns an anonymous type with the properties "left" and "right" corresponding to elements from the left and right collections. Then, you may iterate over the result to perform your action.

like image 55
Michael Petito Avatar answered Jan 02 '26 00:01

Michael Petito


I think you may have a bit of a misconception with an intersect. If you take the intersect of two lists, as it looks like you're doing, the result will be a single list that contains all of the elements that are in both of the lists.

Thus once you've done

IEnumerable<CrewBase> crewBasesLeft;
IEnumerable<CrewBase> crewBasesRight;
IEnumerable<CrewBase> intersect = crewBasesLeft.Intersect( crewBasesRight,CrewBaseComparer.OnId() );

The IEnumerable in intersect doesn't need left or right.

However, if what you're trying to do is get the left and right in your custom IEqualityComparer, then what you want is an object that looks something like this:

class CrewBaseIdComparer : IEqualityComparer<CrewBase>
{
    public bool Equals(CrewBase left, CrewBase right)
    {
        // your logic
    }

    public int GetHashCode(CrewBase item)
    {
        // your logic
    }
}
like image 26
Gregg Avatar answered Jan 01 '26 22:01

Gregg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!