Reputation: 2785
I have seen a similar example with loops continuing after the last element to reset to first, which is great. However, I am unable to figure out how to add that PLUS start iterating from a specified index of the IList
object.
Assume we have this IList
object with a count of 6. (To simplify I'm only using indices below instead of the full objects.)
[1, 2, 3, 4, 5, 6]
Now assume we need to iterate over this IList
10 times.
=> Iterate 10 times
The expected output based on the above should be:
=> 1, 2, 3, 4, 5, 6, 1, 2, 3, 4
However I'd like to start iterating from #4 for example, so the expected output should now be:
=> 4, 5, 6, 1, 2, 3, 4, 5, 6, 1
(All the numbers above represent the position of the elements in the collection, not the actual objects as ints)
Any ideas on how this is possible with LINQ and C#? Please keep in mind that we're working with an IList
.
Upvotes: 2
Views: 552
Reputation: 186668
I suggest implementing an extension method for looping again and again:
// Let it be general case with IEnumerable<T>
public static class EnumerableExtensions {
public static IEnumerable<T> Loop<T>(this IEnumerable<T> source) {
if (null == source)
throw new ArgumentNullException(name(source));
List<T> list = new List<T>();
foreach (var item in source) {
yield return item;
list.Add(item);
}
// ist.Count > 0 - we can't loop (again and again) over empty list
for (int i = 0; list.Count > 0; i = (i + 1) % list.Count)
yield return list[i];
}
}
Then you can put
List<int> myList = ...
// we start looping infinitely - Loop()
// but take first 10 items only - Take(10)
foreach (var item in myList.Loop().Take(10)) {
...
}
// we start looping infinitely - Loop()
// skip first 4 items - Skip(4)
// then take 11 items only - Take(11)
foreach (var item in myList.Loop().Skip(4).Take(11)) {
...
}
Upvotes: 1
Reputation: 8743
You could write the following extension method:
public static class Extensions
{
public static IEnumerable<T> Iterate<T>(this IList<T> input, int from, int length)
{
for(int i = from; i < from + length; i++)
{
yield return input[i % input.Count];
}
}
}
The modulo division makes sure that you start at 0 again if your index is bigger than the size of the list.
Online demo: https://dotnetfiddle.net/Geqslv
Upvotes: 2
Reputation: 2065
You can use Skip
to skip required number of first elements.
For example:
public IEnumerable<T> GetRolledItems<T>(IList<T> source, int count, int startIndex)
{
return Enumerable.Repeat(source, (count + startIndex) / source.Count() + 1)
.SelectMany(a => a)
.Skip(startIndex)
.Take(count);
}
Upvotes: 0