在C#中动态"解压缩"IEnumerable或最佳替代方案

Mah*_*dsi 7 c# linq algorithm ienumerable enumerator

让我们假设您有一个函数返回一个延迟枚举的对象:

struct AnimalCount
{
    int Chickens;
    int Goats;
}

IEnumerable<AnimalCount> FarmsInEachPen()
{
    ....
    yield new AnimalCount(x, y);
    ....
}
Run Code Online (Sandbox Code Playgroud)

您还有两个消耗两个独立IEnumerables的函数,例如:

ConsumeChicken(IEnumerable<int>);
ConsumeGoat(IEnumerable<int>);
Run Code Online (Sandbox Code Playgroud)

如何调用ConsumeChickenConsumeGoatFarmsInEachPen()预先转换ToList()因为它可能有两个zillion记录,b)没有多线程.

基本上:

ConsumeChicken(FarmsInEachPen().Select(x => x.Chickens));
ConsumeGoats(FarmsInEachPen().Select(x => x.Goats));
Run Code Online (Sandbox Code Playgroud)

但是没有强制双重枚举.

我可以使用多线程来解决它,但是每个列表的缓冲队列都会变得不必要地复杂化.

所以我正在寻找一种方法将AnimalCount枚举器分成两个int枚举器而不进行全面评估AnimalCount.在锁定步骤中一起运行ConsumeGoat并没有问题ConsumeChicken.

我可以感觉到解决方案,但我并不完全在那里.我正在考虑一个辅助函数,它返回一个IEnumerable被输入的函数,ConsumeChicken每次使用迭代器时,它在内部调用ConsumeGoat,从而在锁步中执行这两个函数.当然,除了我不想ConsumeGoat多次打电话..

Mah*_*dsi 1

我想通了,这在很大程度上要归功于@Lee 让我走上的道路。

您需要在两个 zip 之间共享一个枚举器,并使用适配器函数将正确的元素投影到序列中。

private static IEnumerable<object> ConsumeChickens(IEnumerable<int> xList)
{
    foreach (var x in xList)
    {
        Console.WriteLine("X: " + x);
        yield return null;
    }
}

private static IEnumerable<object> ConsumeGoats(IEnumerable<int> yList)
{
    foreach (var y in yList)
    {
        Console.WriteLine("Y: " + y);
        yield return null;
    }
}

private static IEnumerable<int> SelectHelper(IEnumerator<AnimalCount> enumerator, int i)
{
    bool c = i != 0 || enumerator.MoveNext();
    while (c)
    {
        if (i == 0)
        {
            yield return enumerator.Current.Chickens;
            c = enumerator.MoveNext();
        }
        else
        {
            yield return enumerator.Current.Goats;
        }
    }
}

private static void Main(string[] args)
{
    var enumerator = GetAnimals().GetEnumerator();

    var chickensList = ConsumeChickens(SelectHelper(enumerator, 0));
    var goatsList = ConsumeGoats(SelectHelper(enumerator, 1));

    var temp = chickensList.Zip(goatsList, (i, i1) => (object) null);
    temp.ToList();

    Console.WriteLine("Total iterations: " + iterations);
}
Run Code Online (Sandbox Code Playgroud)

  • 这依赖于这样一个事实:“Enumerable.Zip()”交替调用每个序列的枚举器,并且显然第二个枚举器在第一个枚举器之前被调用。[这些事实都没有得到文档的保证](http://msdn.microsoft.com/en-us/library/dd267698.aspx),这意味着此解决方案可能并不总是有效,或者可能在未来版本中突然停止工作.Net 的。 (2认同)