无限重复一次可枚举

是否有可枚举的扩展方法无限期地重复可枚举?

因此,例如,给定一个可返回的枚举:[“a”,“b”,“c”]。 我想要一种返回无限重复序列的方法[“a”,“b”,“c”,“a”,“b”,“c”,“a”,“b”,“c”…… ]

这听起来有点像Observable.Repeat ,除了我想在IEnumerables上操作。

Enumerable.Repeat仅从单个元素生成可枚举。

我不知道LINQ内置的任何内容,但创建自己的内容非常简单:

 public static IEnumerable RepeatIndefinitely(this IEnumerable source) { while (true) { foreach (var item in source) { yield return item; } } } 

请注意,这多次评估source – 您可能只想这样做一次,创建一个副本:

 public static IEnumerable RepeatIndefinitely(this IEnumerable source) { var list = source.ToList(); while (true) { foreach (var item in list) { yield return item; } } } 

笔记:

  • 创建序列的副本意味着可以自由地修改原始序列,而不必担心此代码同时迭代它。
  • 当然,创建序列的副本意味着它需要足够小以适应内存。 这可能不太理想。
  • 这只会在您开始迭代结果时创建一个副本。 这很容易令人惊讶。 另一种方法是使用非迭代器方法创建副本,然后委托给私有迭代器方法。 这是LINQ中用于参数validation的方法。
  • 副本很浅 – 例如,如果源是StringBuilder引用的序列,那么对象本身的任何更改仍然可见。

你不能使用Repeat + SelectMany吗?

 var take100ABC = Enumerable.Repeat(new[] { "A", "B", "C" }, 100) .SelectMany(col => col); 

在我看来,扩展方法只有在经常需要时才有用。 我怀疑你经常需要RepeatIndefinitely 。 但是在许多情况下, RepeatWhile可能很方便。 你也可以无限重复。

所以这是我的第一次尝试:

 public static IEnumerable RepeatWhile(this IEnumerable source, Func predicate) { TSource item = default(TSource); do { foreach (TSource current in source) { item = current; yield return item; } } while (predicate(item)); yield break; } 

您可以将它用于“无限”重复,例如以这种方式:

 string[] collection = { "A", "B", "C"}; var infiniteCollection = collection.RepeatWhile(s => s == s); List take1000OfInfinite = infiniteCollection.Take(1000).ToList(); 

您可以创建一个简单的RepeatForever扩展并在序列上使用它,然后在序列序列上使用SelectMany来展平它。

 public static IEnumerable RepeatForever(this T item) { for(;;) yield return item; } public static IEnumerable RepeatSequenceForever(this IEnumerable seq) { return seq.RepeatForever().SelectMany(x => x); } 

如果你可以使用System.Interactive(aka Ix)的 NuGet包,这是另一个选项,只需使用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 }