I have a library that only accepts a proprietary immutable collection type. I would like to have a function that accepts one of these collections and performs some changes to this collection by returning a new collection that contains the changes made.
I would like to use a LINQ syntax instead of copying this collection to a List and back.
Add operations is easy for me: concat the enumerable with another one. But what about Replace (at the given index, return the value given instead of that IEnumerable's value), Insert (at given index, return the given value and then continue iterating over the IEnumerable) or Delete (at given index, skip the IEnumerable's value)?
Are there functions like this available in the .NET framework or in another library? If not, how would I go about implementing these functions?
You can make your own extensions for these operations:
Add
public static IEnumerable<T> Add<T>(this IEnumerable<T> enumerable, T value)
{
foreach (var item in enumerable)
yield return item;
yield return value;
}
or:
public static IEnumerable<T> Add<T>(this IEnumerable<T> enumerable, T value)
{
return enumerable.Concat(new T[] { value });
}
Insert
public static IEnumerable<T> Insert<T>(this IEnumerable<T> enumerable, int index, T value)
{
int current = 0;
foreach (var item in enumerable)
{
if (current == index)
yield return value;
yield return item;
current++;
}
}
or
public static IEnumerable<T> Insert<T>(this IEnumerable<T> enumerable, int index, T value)
{
return enumerable.SelectMany((x, i) => index == i ? new T[] { value, x } : new T[] { x });
}
Replace
public static IEnumerable<T> Replace<T>(this IEnumerable<T> enumerable, int index, T value)
{
int current = 0;
foreach (var item in enumerable)
{
yield return current == index ? value : item;
current++;
}
}
or
public static IEnumerable<T> Replace<T>(this IEnumerable<T> enumerable, int index, T value)
{
return enumerable.Select((x, i) => index == i ? value : x);
}
Remove
public static IEnumerable<T> Remove<T>(this IEnumerable<T> enumerable, int index)
{
int current = 0;
foreach (var item in enumerable)
{
if (current != index)
yield return item;
current++;
}
}
or
public static IEnumerable<T> Remove<T>(this IEnumerable<T> enumerable, int index)
{
return enumerable.Where((x, i) => index != i);
}
Then you can make calls like this:
IEnumerable<int> collection = new int[] { 1, 2, 3, 4, 5 };
var added = collection.Add(6); // 1, 2, 3, 4, 5, 6
var inserted = collection.Insert(0, 0); // 0, 1, 2, 3, 4, 5
var replaced = collection.Replace(1, 22); // 1, 22, 3, 4, 5
var removed = collection.Remove(2); // 1, 2, 4, 5