Although there isn't much left to add to the actual use case OP mentioned, considering the general problem of inserting a value in the correct order in an ordered sequence, a more time and space efficient solution exists.
public static IEnumerable<T> InsertPreservingOrder<T> (this IEnumerable<T> sortedSequence, T value)
where T : IComparable<T>
{
return sortedSequence.TakeWhile(x => x.CompareTo(value) < 0)
.Append(value)
.Concat(sortedSequence.SkipWhile(x => x.CompareTo(value) <= 0));
}
where Append
is syntactic sugar for .Concat(new{...})
as per @codesparkle's answer:
public static IEnumerable<T> Append<T>(this IEnumerable<T> sequence, params T[] items)
{
return sequence.Concat(items);
}
This operation is of constant (O(1)) space, linear (O(n)) time and lazy.
Especially useful in situations like this :
var customValue = 15;
var defaultValues = Enumerable.Range(1, 10000000).Select(x_ => x_ * 10);
var items = defaultValues.InsertPreservingOrder(customValue);
// then later
items.Take(10).ToList().ForEach(Console.WriteLine);
I also think this method is a clear improvement in capturing programmer's intent w.r.t. the original version, regardless of asymptotic complexity.
It reifies an idea; therefore can be reused, whenever the current value of a variable would be added in a collection of default options. Its name makes clear both the precondition that first parameter is assumed to be already sorted, and the postcondition that the return value is also sorted. However it leaves the distinctness condition opaque.
Though I'd still prefer a simple defaultValues.Append(customValue).ToSortedSet()