Repeat an enumerable indefinitely
Can't you use Repeat
+ SelectMany
?
var take100ABC = Enumerable.Repeat(new[] { "A", "B", "C" }, 100)
.SelectMany(col => col);
In my opinion an extension method is useful only if you need it often. I doubt that you need a RepeatIndefinitely
often. But a RepeatWhile
could be handy in many cases. You could it also for an infinite repetition.
So here is my my first attempt:
public static IEnumerable<TSource> RepeatWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
TSource item = default(TSource);
do
{
foreach (TSource current in source)
{
item = current;
yield return item;
}
}
while (predicate(item));
yield break;
}
You can use it for your "infinite" repetion for example in this way:
string[] collection = { "A", "B", "C"};
var infiniteCollection = collection.RepeatWhile(s => s == s);
List<string> take1000OfInfinite = infiniteCollection.Take(1000).ToList();
Here is another option if you can use NuGet package of System.Interactive (aka Ix), just use Repeat()
.
var sequence = Enumerable.Range(1, 3).Repeat();
foreach (var item in sequence.Take(10))
{
Console.WriteLine(item); // 1, 2, 3, 1, 2, 3, 1, 2, 3, 1
}
I don't know of anything built into LINQ, but it's really easy to create your own:
public static IEnumerable<T> RepeatIndefinitely<T>(this IEnumerable<T> source)
{
while (true)
{
foreach (var item in source)
{
yield return item;
}
}
}
Note that this evaluates source
multiple times - you might want to make it only do so once, creating a copy:
public static IEnumerable<T> RepeatIndefinitely<T>(this IEnumerable<T> source)
{
var list = source.ToList();
while (true)
{
foreach (var item in list)
{
yield return item;
}
}
}
Notes:
- Creating a copy of the sequence means the original sequence may be modified freely without worrying about this code iterating over it concurrently.
- Creating a copy of the sequence means it needs to be sufficiently small to fit in memory, of course. That may not be ideal.
- This will only create a copy when you start iterating over the result. That could easily be surprising. An alternative approach would be to have a non-iterator method which created a copy, then delegated to a private iterator method. This is the approach used for argument validation in LINQ.
- The copy is shallow - if the source is a sequence of
StringBuilder
references, for example, then any changes to the objects themselves will still be visible.