Skip to content

Instantly share code, notes, and snippets.

@MrAntix
Created March 7, 2018 14:09
Show Gist options
  • Save MrAntix/5b3cb31b5642c98a30e3327f246309f8 to your computer and use it in GitHub Desktop.
Save MrAntix/5b3cb31b5642c98a30e3327f246309f8 to your computer and use it in GitHub Desktop.
Apply changes to a list with a serializable list of add/updates and removes
public class Changes<T>
{
public Changes(
IEnumerable<T> toAddOrUpdate = null,
IEnumerable<T> toRemove = null)
{
ToAddOrUpdate = toAddOrUpdate?.ToImmutableArray() ?? ImmutableArray<T>.Empty;
ToRemove = toRemove?.ToImmutableArray() ?? ImmutableArray<T>.Empty;
}
public IImmutableList<T> ToAddOrUpdate { get; }
public IImmutableList<T> ToRemove { get; }
public Changes<T> AddOrUpdate(params T[] items)
{
return new Changes<T>(
ToAddOrUpdate.Concat(items),
ToRemove);
}
public Changes<T> Remove(params T[] items)
{
return new Changes<T>(
ToAddOrUpdate,
ToRemove.Concat(items));
}
}
public static class Changes
{
public static Changes<T> AddOrUpdate<T>(params T[] items)
{
return new Changes<T>(items, null);
}
public static Changes<T> Remove<T>(params T[] items)
{
return new Changes<T>(null, items);
}
}
public static class ChangesExtensions
{
public static IImmutableList<T> Apply<T>(
this IEnumerable<T> items,
Changes<T> changes,
IEqualityComparer<T> comparer = null)
{
var result = items.ToList();
if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}
foreach (var toAddUpdate in changes.ToAddOrUpdate)
{
var found = false;
for (var i = 0; i < result.Count; i++)
if (comparer.Equals(result[i], toAddUpdate))
{
result[i] = toAddUpdate;
found = true;
break;
}
if (!found) result.Add(toAddUpdate);
}
return result.Except(changes.ToRemove).ToImmutableArray();
}
}
public class ChangesTests
{
[Fact]
public void adds()
{
var a = new[] { Guid.NewGuid(), Guid.NewGuid() };
var toAdd = new[] { Guid.NewGuid() };
var changes = Changes.AddOrUpdate(toAdd);
var b = a.Apply(changes);
Assert.Equal(a.Concat(toAdd), b);
}
[Fact]
public void remove()
{
var a = new[] { Guid.NewGuid(), Guid.NewGuid() };
var toRemove = a.Take(1).ToArray();
var changes = Changes.Remove(toRemove);
var b = a.Apply(changes);
Assert.Equal(a.Skip(1), b);
}
[Fact]
public void update()
{
var a = new[] { new Thing(""), new Thing("") };
var toUpdate = new[] { new Thing(a[0].Key, "Updated") };
var changes = Changes.AddOrUpdate(toUpdate);
var b = a.Apply(changes);
Assert.Equal(toUpdate[0].Value, b[0].Value);
Assert.Same(a[1], b[1]);
}
public class Thing : IEquatable<Thing>
{
public Thing(Guid key, string value)
{
Key = key;
Value = value;
}
public Thing(string value) :
this(Guid.NewGuid(), value)
{
}
public Guid Key { get; }
public string Value { get; }
bool IEquatable<Thing>.Equals(Thing other)
{
return Key == other.Key;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment