从预设位置开始迭代,到达终点后继续迭代
Iterate starting from a preset position and continue iterating after end is reached
我见过一个类似的例子,在最后一个元素重置为第一个元素之后继续循环,这很棒。但是,我无法弄清楚如何添加 PLUS 从 IList
对象的指定索引开始迭代。
假设我们有一个计数为 6 的 IList
对象。(为简化起见,我只使用下面的索引而不是完整的对象。)
[1, 2, 3, 4, 5, 6]
现在假设我们需要迭代此 IList
10 次。
=> Iterate 10 times
基于以上的预期输出应该是:
=> 1, 2, 3, 4, 5, 6, 1, 2, 3, 4
但是我想从 #4 开始迭代,所以现在预期的输出应该是:
=> 4, 5, 6, 1, 2, 3, 4, 5, 6, 1
(以上所有数字代表集合中元素的位置,并非作为int的实际对象)
关于如何使用 LINQ 和 C# 实现这一点有什么想法吗?请记住,我们使用的是 IList
.
您可以使用 Skip
跳过所需数量的第一个元素。
例如:
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);
}
您可以编写如下扩展方法:
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];
}
}
}
如果您的索引大于列表的大小,模除法确保您再次从 0 开始。
我建议实现一个 扩展方法 来一次又一次地循环:
// 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];
}
}
那你可以把
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)) {
...
}
我见过一个类似的例子,在最后一个元素重置为第一个元素之后继续循环,这很棒。但是,我无法弄清楚如何添加 PLUS 从 IList
对象的指定索引开始迭代。
假设我们有一个计数为 6 的 IList
对象。(为简化起见,我只使用下面的索引而不是完整的对象。)
[1, 2, 3, 4, 5, 6]
现在假设我们需要迭代此 IList
10 次。
=> Iterate 10 times
基于以上的预期输出应该是:
=> 1, 2, 3, 4, 5, 6, 1, 2, 3, 4
但是我想从 #4 开始迭代,所以现在预期的输出应该是:
=> 4, 5, 6, 1, 2, 3, 4, 5, 6, 1
(以上所有数字代表集合中元素的位置,并非作为int的实际对象)
关于如何使用 LINQ 和 C# 实现这一点有什么想法吗?请记住,我们使用的是 IList
.
您可以使用 Skip
跳过所需数量的第一个元素。
例如:
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);
}
您可以编写如下扩展方法:
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];
}
}
}
如果您的索引大于列表的大小,模除法确保您再次从 0 开始。
我建议实现一个 扩展方法 来一次又一次地循环:
// 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];
}
}
那你可以把
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)) {
...
}