Today I needed a method to replace all 'x' values in a said collection. Since there is no such method by default in .NET I wrote my own:
[Pure]
public static IEnumerable<T> Replace<T>(this IEnumerable<T> source, T oldValue, T newValue)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
List<T> newValues = new List<T>();
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
newValues.Add(enumerator.Current.Equals(oldValue) ? newValue : enumerator.Current);
}
}
return newValues;
}
It's pretty short and does the job right in a reasonable amount of time.
I also tested few other solutions:
[Pure]
public static IEnumerable<T> Replace1<T>(this IEnumerable<T> source, T oldValue, T newValue)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
yield return enumerator.Current.Equals(oldValue) ? newValue : enumerator.Current;
}
}
}
[Pure]
public static IEnumerable<T> Replace2<T>(this IEnumerable<T> source, T oldValue, T newValue)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
List<T> newValues = new List<T>(source);
for (int i = 0; i < newValues.Count; i++)
{
if (newValues[i].Equals(oldValue))
{
newValues[i] = newValue;
}
}
return newValues;
}
But they are all slower than the former. The only advantage is in the function which utilizes iterator because it's a bit shorter but it's actually the slowest out of the three.
Here are my benchmark results for each method running 1 million times:
Replace
Slowest: 207ms
Average: 177.8ms
Fastest: 161ms
Replace 1
Slowest: 353ms
Average: 293.9ms
Fastest: 253ms
Replace 2
Slowest: 344ms
Average: 276.4ms
Fastest: 252ms
Feel free to comment on anything you feel like can be improved.
Here are some of my questions:
- Are there any flaws in my function?
- Are there any improvements that can be made?
- Why didn't Microsoft include this in the .NET framework?
List<T>
constructing version has a terrible performance downside:SomeGiantSequence.Replace("bad", "good").Take(5);
\$\endgroup\$