views:

46

answers:

1

I'm having a problem with finding out which children to add, update and delete when I'm dealing with two lists one with the old chidren (from db) and the other list with the modified children (from user input).

Currently I have to loop through the lists and compare to find the difference.

Does anyone know of a better way of doing this without having to loop through the lists?

+4  A: 

The IEnumerable.Except extension method is perfect for this. In most cases you will want to use the overload that accepts an IEqualityComparer<T> to compare by identity, unless you have carefully overridden Equals and GetHashCode in your objects.

Given

IEnumerable<Company> oldList, IEnumerable<Company> newList

The code is:

var companiesToAdd = newList.Except(oldList).ToArray();
var companiesToRemove = oldList.Except(newList).ToArray();

The ToArray() calls are there so that you can make changes to the original list while iterating the add and remove lists.

Edit: Below are two utility classes that make this operation easy. Usage is

var diff = new DiffIEnumerable<Company>(oldList, newList, x => x.CompanyId);
var companiesToAdd = diff.InYNotX;
var companiesToRemove = diff.InXNotY;

public class IdentityComparer<T> : IEqualityComparer<T> where T : class
{
    private readonly Func<T, object> _getIdentity;

    public IdentityComparer(Func<T, object> getIdentity)
    {
        _getIdentity = getIdentity;
    }

    public bool Equals(T x, T y)
    {
        if (x == null || y == null)
        {
            return false;
        }
        return _getIdentity(x).Equals(_getIdentity(y));
    }

    public int GetHashCode(T obj)
    {
        return _getIdentity(obj).GetHashCode();
    }
}

public class DiffIEnumerable<T> where T : class
{
    public DiffIEnumerable(IEnumerable<T> x, IEnumerable<T> y, Func<T, object> getIdentity) :
        this(x, y, new IdentityComparer<T>(getIdentity))
    { }

    public DiffIEnumerable(IEnumerable<T> x, IEnumerable<T> y, IEqualityComparer<T> comparer)
    {
        InXAndY = x.Intersect(y, comparer).ToArray();
        InXNotY = x.Except(y, comparer).ToArray();
        InYNotX = y.Except(x, comparer).ToArray();
    }

    public IEnumerable<T> InXAndY { get; private set; }

    public IEnumerable<T> InXNotY { get; private set; }

    public IEnumerable<T> InYNotX { get; private set; }

}
Jamie Ide
That's pretty slick..will be adding this to my bag-o-tricks +1
DanP
That's quality! thanks Jamie.
Calum Bett