J. Davidson
J. Davidson

Reputation: 3307

Taking union of two lists based on column

I am taking a union of two lists using Linq to Sql. Using List1 and List2:

 var tr = List1.Union(List2).ToList();

Union works fine, but the problem is it is checking each column and removes some of the rows that I want. So I was wondering if there is a a way I can perform a union based on one column only, like let's say id, of each list?

Something Like:

var t = List1.id.Union(List2.id).ToList();

This doesn't work, but I was wondering if there is a way to do this, either with LINQ or T-SQL

Upvotes: 2

Views: 2400

Answers (4)

Mitko Keckaroski
Mitko Keckaroski

Reputation: 1040

Try this:

var merged = new List<Person>(list1);
merged.AddRange(list2.Where(p2 => 
                list1.All(p1 => p1.Id != p2.Id)));

Upvotes: 0

m4a
m4a

Reputation: 187

try somthing this

var List3 = List1.Join(
List2, 
l1 => l1.Id,
l2 => l2.Id,
(l1, l2) => new Model
{
   Id = l1.Id,
   Val1 = l1.Val1 or other,
   Val2 = l2.Val2  or other
});

for more details you can show your model

Upvotes: 0

Rapha&#235;l Althaus
Rapha&#235;l Althaus

Reputation: 60493

You should use this Union() overload (with a custom equality comparer) , or something like this:

list1.Concat(list2).GroupBy(x => x.DateProperty).Select(m => m.First());

The first solution is certainly more efficient.

Upvotes: 5

It&#39;sNotALie.
It&#39;sNotALie.

Reputation: 22794

Sure, you need a custom IEqualityComparer with Union. I have one that's really dynamic, big block of code incoming though:

public class PropertyEqualityComparer<TObject, TProperty> 
    : IEqualityComparer<TObject>
{
    Func<TObject, TProperty> _selector;
    IEqualityComparer<TProperty> _internalComparer;
    public PropertyEqualityComparer(Func<TObject, TProperty> propertySelector,
        IEqualityComparer<TProperty> innerEqualityComparer = null)
    {
        _selector = propertySelector;
        _internalComparer = innerEqualityComparer;
    }
    public int GetHashCode(TObject obj)
    {
        return _selector(obj).GetHashCode();
    }
    public bool Equals(TObject x, TObject y)
    {
        IEqualityComparer<TProperty> comparer = 
            _internalComparer ?? EqualityComparer<TProperty>.Default;
        return comparer.Equals(_selector(x), _selector(y));
    }
}
public static class PropertyEqualityComparer
{
    public static PropertyEqualityComparer<TObject, TProperty>
        GetNew<TObject, TProperty>(Func<TObject, TProperty> propertySelector)
    { 
        return new PropertyEqualityComparer<TObject, TProperty>
            (propertySelector);
    }
    public static PropertyEqualityComparer<TObject, TProperty>
        GetNew<TObject, TProperty>
        (Func<TObject, TProperty> propertySelector, 
        IEqualityComparer<TProperty> comparer)
    { 
        return new PropertyEqualityComparer<TObject, TProperty>
            (propertySelector, comparer);
    }
}

Now, all you need to do is call Union with that equality comparer (instantiated with a lambda that fits your circumstance):

var tr = List1.Union(List2, PropertyEqualityComparer.GetNew(n => n.Id)).ToList();

Upvotes: 1

Related Questions