Search code examples
c#linqlistintersectexcept

Combine two lists of entities with a condition


Say I have a class defined as

class Object
{
    public int ID { get;set; }
    public string Property { get; set; }

    public override bool Equals(object obj)
    {
        Object Item = obj as Object;
        return Item.ID == this.ID;
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + ID.GetHashCode();
        return hash;       
    }
}

And two lists, defined like so:

List<Object> List1;
List<Object> List2;

These two lists contain objects where ID fields could be the same, but Property fields may or may not. I want to have a result of all objects contained in List1 together with all objects contained in List2, with the condition thatPropertyfield must be set to"1"if it is set to"1"` in any of those lists. The result must contain distinct values (distinct IDs).

For example, if we have 2 lists like this:

List1 
-----  
ID = 0, Property = "1"
ID = 1, Property = ""
ID = 2, Property = "1"
ID = 3, Property = ""

List2
-----
ID = 1, Property = "1"
ID = 2, Property = ""
ID = 3, Property = ""

I need a result to look like this:

Result
-------
ID = 0, Property = "1"
ID = 1, Property = "1"
ID = 2, Property = "1"
ID = 3, Property = "" 

Currently it works like this:

var Result = List1.Except(List2).Concat(List2.Except(List1));
var Intersection = List1.Intersect(List2).ToList();
Intersection.ForEach(x => {
    x.Property = List1.Single(y => y.ID == x.ID).Property == "1" ? "1" : List2.Single(y => y.ID == x.ID).Property == "1" ? "1" : "";
});

Result = Result.Concat(Intersection);

...but ForEach is very slow. Can someone suggest a faster way?


Solution

  • var result = List1.Concat(List2)
                      .GroupBy(o => o.ID)
                      .Select(g => new Object() { 
                                       ID=g.Key,
                                       Property=g.Any(o=>o.Property=="1")?"1":""
                       })
                      .ToList();