是否有可枚举的扩展方法可以无限地重复枚举?
例如,给定一个返回值为 ["a", "b", "c"] 的可枚举对象。我想要一个可以返回无限重复序列 ["a", "b", "c", "a", "b", "c", "a", "b", "c" ... ] 的方法。
这听起来有点像 Observable.Repeat,但我想在 IEnumerables 上操作。
Enumerable.Repeat 只能从单个元素生成可枚举对象。
是否有可枚举的扩展方法可以无限地重复枚举?
例如,给定一个返回值为 ["a", "b", "c"] 的可枚举对象。我想要一个可以返回无限重复序列 ["a", "b", "c", "a", "b", "c", "a", "b", "c" ... ] 的方法。
这听起来有点像 Observable.Repeat,但我想在 IEnumerables 上操作。
Enumerable.Repeat 只能从单个元素生成可枚举对象。
我不知道LINQ内置了什么,但是创建自己的方法非常简单:really
public static IEnumerable<T> RepeatIndefinitely<T>(this IEnumerable<T> source)
{
while (true)
{
foreach (var item in source)
{
yield return item;
}
}
}
请注意,这会多次评估source
- 你可能希望只评估一次并创建一个副本:
public static IEnumerable<T> RepeatIndefinitely<T>(this IEnumerable<T> source)
{
var list = source.ToList();
while (true)
{
foreach (var item in list)
{
yield return item;
}
}
}
注意:
StringBuilder
引用,那么对对象本身所做的任何更改仍将可见。.ToList
创建另一个集合之前,尝试将其转换为集合会更好吗?但是我必须承认,我对ToList
的原因并没有完全理解。也许你可以稍微详细解释一下这个。 - Tim SchmelterToList
总是会创建一个副本,这意味着在其他代码修改原始集合时,迭代结果肯定不会出现任何问题。我没有太多时间在这个答案中详细解释,但我会添加一些说明性文字。 - Jon Skeetbool
,例如 createCopy
,以获得两全其美的效果。 - Wai Ha Lee你不能使用Repeat
+ SelectMany
吗?
var take100ABC = Enumerable.Repeat(new[] { "A", "B", "C" }, 100)
.SelectMany(col => col);
在我看来,扩展方法只有在需要频繁使用时才有用。我怀疑你并不经常需要一个 RepeatIndefinitely
。但是一个 RepeatWhile
在许多情况下都很方便。你也可以用它进行无限重复。
所以这是我的第一次尝试:
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;
}
您可以使用它进行“无限”重复,例如:
string[] collection = { "A", "B", "C"};
var infiniteCollection = collection.RepeatWhile(s => s == s);
List<string> take1000OfInfinite = infiniteCollection.Take(1000).ToList();
RepeatWhile
,也可以(滥用)用于您的要求。 - Tim Schmelter如果您可以使用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
}
RepeatForever
扩展并在序列上使用它,然后对序列的序列进行SelectMany
操作以展开它。public static IEnumerable<T> RepeatForever<T>(this T item)
{
for(;;) yield return item;
}
public static IEnumerable<T> RepeatSequenceForever<T>(this IEnumerable<T> seq)
{
return seq.RepeatForever().SelectMany(x => x);
}
如果您不介意增加一个依赖项,您可以使用MoreLinq中的Repeat方法。
它正好做你需要的事情。 例如:
var sequence = new[] {"a", "b", "c"};
var generator = sequence.Repeat();
var boundSequence = Enumerable.Range(0,10).Zip(generator);
foreach (var (i,val) in boundSequence)
{
Console.WriteLine($"{i}: {val}");
}
输出这个:
0: a
1: b
2: c
3: a
4: b
5: c
6: a
7: b
8: c
9: a
public static IEnumerable<T> RepeatIndefinitely<T>(this IEnumerable<T> source) {
var t = source.GetEnumerator();
while (t.MoveNext()) {
do {
yield return t.Current;
} while (t.MoveNext());
t = source.GetEnumerator();
}
throw new InvalidOperationException("Sequence contains no elements, possibly after reset.");
}
IEnumerable
呢? - Emil Lundberg