2
\$\begingroup\$

The desired behavior would be:

    [TestMethod]
    public void Compare_Value_Identity()
    {
        var source = new[] { 1, 2 };
        var modified = new[] { 2, 3 };

        var (inserted, deleted) = source.Compare(modified);

        CollectionAssert.AreEqual(new[] { 3 }, inserted.ToArray());
        CollectionAssert.AreEqual(new[] { 1 }, deleted.ToArray());
    }

And:

    [TestMethod]
    public void Compare_Id_Identity()
    {
        var source = new[] { (1, "A"), (2, "B"), (3, "C") };
        var modified = new[] { (2, "B"), (3, "D"), (4, "E") };

        var (inserted, updated, deleted) = source.Compare(modified, x => x.Item1);

        CollectionAssert.AreEqual(new[] { (4, "E") }, inserted.ToArray());
        CollectionAssert.AreEqual(new[] { (3, "D") }, updated.ToArray());
        CollectionAssert.AreEqual(new[] { (1, "A") }, deleted.ToArray());
    }

Library code is:

public static class SequenceChange
{
    public static (IEnumerable<T> Inserted, IEnumerable<T> Deleted) Compare<T>(
        this IEnumerable<T> source, IEnumerable<T> modified) =>
        source.Compare(modified, EqualityComparer<T>.Default);

    public static (IEnumerable<T> Inserted, IEnumerable<T> Deleted) Compare<T>(
        this IEnumerable<T> source, IEnumerable<T> modified, IEqualityComparer<T> comparer) =>
        (modified.Except(source, comparer), source.Except(modified, comparer));

    public static (IEnumerable<T> Inserted, IEnumerable<T> Updated, IEnumerable<T> Deleted) Compare<T, TKey>(
        this IEnumerable<T> source, IEnumerable<T> modified, Func<T, TKey> keySelector) =>
        source.Compare(modified, keySelector, EqualityComparer<T>.Default);

    public static (IEnumerable<T> Inserted, IEnumerable<T> Updated, IEnumerable<T> Deleted) Compare<T, TKey>(
        this IEnumerable<T> source, IEnumerable<T> modified, Func<T, TKey> keySelector, IEqualityComparer<T> comparer) =>
        (modified.ExceptBy(source, keySelector),
        from s in source
        join m in modified on keySelector(s) equals keySelector(m)
        where !comparer.Equals(s, m)
        select m,
        source.ExceptBy(modified, keySelector));
}  
\$\endgroup\$
5
  • \$\begingroup\$ where is the method ExceptBy from ? Some library ? \$\endgroup\$ Dec 16, 2019 at 8:13
  • \$\begingroup\$ @Disappointed MoreLinq, issue \$\endgroup\$ Dec 16, 2019 at 8:41
  • \$\begingroup\$ not looking what code produces, what is expected result for comparison of { (1, "A"), (1, "F") } and { (1, "B"), (1, "D"), (1, "E") } ? For me that is not clear ... Code returns confusing results with 6 updated items (!) which is more than the total number of both sequences \$\endgroup\$ Dec 16, 2019 at 10:14
  • \$\begingroup\$ @Disappointed You do not observe id identity, which is supposed to be there by definition. Imagine business model collection to be synced with database. You would reread business models from the db and compare with the provided modified collection using primary key id to match old and new records to calculate necessary syncing operations. There could not be and should not be any key duplication as long as id identity is observed. Do we need a check with an exception? Probably yes. \$\endgroup\$ Dec 16, 2019 at 14:42
  • \$\begingroup\$ Yes, probably validation and exception is needed for cases when user provides non-unique keySelector \$\endgroup\$ Dec 16, 2019 at 14:52

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.