【发布时间】:2014-10-16 07:35:49
【问题描述】:
我经常需要在有IEnumerable<T> A、IEnumerable<T> B 的地方执行操作,并且我想创建IEnumerable<T> C,其中 C 将从 A 获取 2T,然后从 B 获取 1T,然后再次从 A 获取 2T,然后从 B 获取 1T等等 - AABAABAAB...
C# 中是否有一些语言结构,也许是一些 LINQ 表达式可以轻松完成。
现在我编写了一个小助手类,使我能够做到这一点:
var C = EnumerableMixer(new int[]{2, 1}, A, B):
public class EnumerableMixer<T> : IEnumerable<T>
{
int[] Quantity;
IEnumerable<T>[] Args;
public EnumerableMixer(int[] quantity, params IEnumerable<T>[] args)
{
this.Quantity = quantity;
this.Args = args;
if (quantity.Length != args.Length)
throw new NotImplementedException("Quantity must have same length as number of args!");
}
IEnumerable<T> Mix
{
get
{
var available = new List<int>(Quantity.Length);
var enumerators = new List<IEnumerator<T>>(Quantity.Length);
for (int i = 0; i < Quantity.Length; ++i)
{
available.Add(i);
enumerators.Add(Args[i].GetEnumerator());
}
while (available.Count > 0)
{
for (int i = 0; i < available.Count; ++i)
{
var id = available[i];
for (int j = 0; j < Quantity[id]; ++j)
{
if (enumerators[id].MoveNext())
yield return enumerators[id].Current;
else
{
available.RemoveAt(i);
i--;
break;
}
}
}
}
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return Mix.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
【问题讨论】:
-
如果一个枚举在另一个枚举之前完全枚举,会发生什么?例如:A= {1,4,8,9},B={0,1,2,3,4,5,6}。应该是 {1,4,0,8,9,1,2,3,4,5,6} 还是 {1,4,0,8,9,1} 甚至是 {1,4,0,8 ,9} 还是抛出异常?
-
如果一个枚举不包含混合数量的多个元素倍数会发生什么?例如:A= {1,4,8},B={0,1,2,3,4,5,6}。应该是 {1,4,0,8,1,2,3,4,5,6} 还是 {1,4,0,8} 还是抛出异常?
-
你知道Reactive Extensions吗?您谈论混合各种“提要”的方式对我来说感觉如此 Rx。在 Rx 中,有各种运算符可以将 IObservable 序列无缝地组合在一起,这对您来说真的很有用。我个人会认真考虑你的情况。
-
@CédricBignon 你的问题很好,我认为对于一般解决方案,我们必须有几个选项来处理枚举结束的枚举。
-
@julealgon 我认为 rx 在这里没有太大帮助
标签: c# .net linq ienumerable enumerable