2

My goal is to compare to lists and update values on list A with values from list B. Along with that, I want it to work like a left join and keep all values from list A even if they didn't get updated and detect multiple matches.

What I have tried so far is below.

The Setup

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string UpdateMe { get; set; }

    public static List<Person> CreateList()
    {
        return new List<Person>
        {
            new Person { LastName = "Barton", FirstName = "Clint" },
            new Person { LastName = "Stark", FirstName = "Tony" },
            new Person { LastName = "Parker", FirstName = "Peter" }   
        };
    }

    public static List<Person> CreateListTwo()
    {
        return new List<Person>
        {
            new Person { LastName = "Barton", FirstName = "Clint", UpdateMe = "Updated"},
            new Person { LastName = "Stark", FirstName = "Tony", UpdateMe = "Updated"},
        };
    }
}

public class FirstLastNameMatch : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.FirstName == y.FirstName 
            && x.LastName == y.LastName;
    }

    public int GetHashCode(Person obj)
    {
        unchecked
        {
            var hash = 17;
            hash = hash * 23 + obj.FirstName.GetHashCode();
            hash = hash * 23 + obj.LastName.GetHashCode();
            return hash;
        }
    }
}

Implementation

static void Main()
{
    var listA = Person.CreateList();
    var listB = Person.CreateListTwo();

    //Attempt
    var result = listA.Join(
        listB,
        x => x,
        y => y,
        (x, y) => new Person
        {
            FirstName = x.FirstName,
            LastName = x.LastName,
            UpdateMe = y.UpdateMe
        },
        new FirstLastNameMatch()
        );

    foreach (var person in result)
    {
        Console.WriteLine($"Name: {person.FirstName} {person.LastName} " +
                          $"UpdateMe: {person.UpdateMe} ");
    }
}

There problem I run into here is that it is only an inner join and not a left join. I have found a way to do the left join but I cannot figure out how to pass in the IEqualityComparer into this syntax.

var result = from personA in listA
             join personB in listB on new {personA.FirstName, personA.LastName } equals new { personB.FirstName, personB.LastName }
                 into buffer
             from subPerson in buffer.DefaultIfEmpty()
             select new Person
             {
                 FirstName = personA.FirstName,
                 LastName = personA.LastName,
                 UpdateMe = (subPerson == null ? string.Empty : subPerson.UpdateMe)
             };

The real catch is that once I am able to complete the left join while injecting the comparison criteria, I still need to detect duplicates. I need to be able to identify if a person from listA matches to more than one person in listB. It is alright if listA had duplicates though.

End Goal

Left join 2 lists with dynamic matching criteria.
Detect multiple matches from the right list.
I need to update a static list of properties on the left list with the match from the right list.

Matt Rowland
  • 4,575
  • 4
  • 25
  • 34
  • Using your Join solution for getting results, I was able to see if there are multiple matches from right list. I am not sure why you were saying that you could not do this? Also, equals performs an equijoin and is not same as ==. So you may not be able to pass a dynamic matching criteria. See this link, https://msdn.microsoft.com/en-us/library/bb311040.aspx – Martin Jan 16 '16 at 00:36
  • @Martin How where you able to detect the multiple matches? The dynamic matching criteria comes from the IEqualityComparer being injected into to join. – Matt Rowland Jan 16 '16 at 00:49
  • I added one more person in CreateListTwo() with the values as {Stark, Tony, Cancelled}; I got four Persons in my console when i executed your solution. One output for Clint Barton, Two for Tony Stark and One for Peter Parker. Correct me if i got it wrong about the multiple matches goal. – Martin Jan 16 '16 at 01:53
  • @Martin Getting multiple matches and identifying them are two separate things. If I was comparing 2 lists of 1,000,000 objects each I would then have to manually look through some sort of output to look for those matches. Then what is the point of using a program at all? I need a way of identifying that a `listA` object was found multiple times in `listB`, like the `Single()` Linq clause does. – Matt Rowland Jan 16 '16 at 01:58

0 Answers0