C# 混合几个IEnumerable<;T>;在C中输入一个#

C# 混合几个IEnumerable<;T>;在C中输入一个#,c#,.net,linq,ienumerable,enumerable,C#,.net,Linq,Ienumerable,Enumerable,我经常需要在我有IEnumerable A,IEnumerable B的地方执行操作,我想创建IEnumerable C,其中C将从A获取2T,然后从B获取1T,然后再从A获取2T,然后从B获取1T,依此类推-aabababaab 在C#中是否有一些语言结构,也许有一些LINQ表达式可以轻松完成 现在,我编写了一个小型助手类,它使我能够: var C=EnumerableMixer(新的int[]{2,1},A,B): 公共类EnumerableMix:IEnumerable { int[]数量

我经常需要在我有
IEnumerable A
IEnumerable B
的地方执行操作,我想创建
IEnumerable C
,其中C将从A获取2T,然后从B获取1T,然后再从A获取2T,然后从B获取1T,依此类推-aabababaab

在C#中是否有一些语言结构,也许有一些LINQ表达式可以轻松完成

现在,我编写了一个小型助手类,它使我能够:

var C=EnumerableMixer(新的int[]{2,1},A,B)

公共类EnumerableMix:IEnumerable
{
int[]数量;
IEnumerable[]Args;
公共EnumerableMixer(int[]数量,params IEnumerable[]参数)
{
这个。数量=数量;
this.Args=Args;
if(quantity.Length!=args.Length)
抛出新的NotImplementedException(“数量必须与参数数量具有相同的长度!”);
}
可数混合
{
得到
{
可用变量=新列表(数量、长度);
变量枚举数=新列表(数量.长度);
对于(int i=0;i0)
{
for(int i=0;i
稍微长一点的解决方案是:

    public IEnumerable<TValue> Mix<TValue>(IEnumerable<TValue> a, IEnumerable<TValue> b)
    {
        var aEnumerator = a.GetEnumerator();
        var bEnumerator = b.GetEnumerator();

        while (true)
        {
            if (!aEnumerator.MoveNext())
            {
                yield break;
            }

            yield return aEnumerator.Current;

            if (!aEnumerator.MoveNext())
            {
                yield break;
            }

            yield return aEnumerator.Current;

            if (!bEnumerator.MoveNext())
            {
                yield break;
            }

            yield return bEnumerator.Current;
        }
    }
公共IEnumerable混合(IEnumerable a,IEnumerable b)
{
var aEnumerator=a.GetEnumerator();
var bEnumerator=b.GetEnumerator();
while(true)
{
如果(!aEnumerator.MoveNext())
{
屈服断裂;
}
收益率返回分子。当前;
如果(!aEnumerator.MoveNext())
{
屈服断裂;
}
收益率返回分子。当前;
如果(!bEnumerator.MoveNext())
{
屈服断裂;
}
收益率-收益率-当前值;
}
}

此解决方案不会创建不必要的对象。如果您不熟悉yield关键字:

这是我的Linq解决方案:

对于每个元素,分配一个索引,然后按正确的顺序获取元素

// for example. You can use with any type
IEnumerable<Int32> listA = new List<Int32>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
IEnumerable<Int32> listB = new List<Int32>() { 101, 102, 103, 104, 105, 106, 107, 108, 109, 110};

// you want 2 of list A and 1 of list B. You can change the values
Int16[] quantity = new Int16[] { 2, 1 };

IEnumerable<Int32> listC = listA.Select((e, i) => new  { element = e, index = (i / (quantity[0]) * (quantity[0] + quantity[1]) + (i%quantity[0]))})
                                .Concat(listB.Select((e, i) => new  { element = e, index = (i / (quantity[1]) * (quantity[0] + quantity[1]) + (i%quantity[1]) + quantity[0])}))
                                .OrderBy(e => e.index)
                                .Select(e => e.element);
关于第二份清单:

index = i/(quantity[1]) * (quantity[0]+quantity[1]) + (i%quantity[1]) + quantity[0]
版本1 这是基于adhie的解决方案。它将比率考虑在内,并在退出该方法之前完全完成这两个序列。
标志
用于跟踪最后一个循环是否产生任何结果。当
标志
为false时,两个序列都将耗尽

public IEnumerable<T> Mix<T>(IEnumerable<T> sequenceA, IEnumerable<T> sequenceB, int ratioA, int ratioB)
{
    var etorA = sequenceA.GetEnumerator();
    var etorB = sequenceB.GetEnumerator();
    bool flag = true;

    while(flag)
    {
        flag = false;

        for(int i = 0; i < ratioA && (flag |= etorA.MoveNext()); i++)
            yield return etorA.Current;

        for(int i = 0; i < ratioB && (flag |= etorB.MoveNext()); i++)
            yield return etorB.Current;
    }
}
public IEnumerable Mix(IEnumerable sequenceA、IEnumerable sequenceB、int ratioA、int ratioB)
{
var etorA=sequenceA.GetEnumerator();
var etorB=sequenceB.GetEnumerator();
布尔标志=真;
while(旗帜)
{
flag=false;
对于(inti=0;i
版本2 与版本1几乎相同,但采用可变数量的序列

public IEnumerable<T> Mix<T>(params KeyValuePair<IEnumerable<T>, uint>[] quantifiedSequences)
{
    var sequences = quantifiedSequences.Select(x => new { Etor = x.Key.GetEnumerator(), Quantity = x.Value });
    bool flag = true;

    while(flag)
    {
        foreach (var sequence in sequences)
            for(int i = 0; i < sequence.Quantity && (flag |= sequence.Etor.MoveNext()); i++)
                yield return sequence.Etor.Current;
    }
}
public IEnumerable混合(参数KeyValuePair[]quantifiedSequences)
{
var sequences=quantifiedSequences.Select(x=>new{Etor=x.Key.GetEnumerator(),Quantity=x.Value});
布尔标志=真;
while(旗帜)
{
foreach(序列中的var序列)
对于(int i=0;i
我不知道为什么这会被否决(除非我错过了什么),这是我在看到OP实现了一个更复杂的版本之前要提出的建议。我不知道你的答案,但它没有选择将2-1比率设置为函数参数,这就是为什么它更简单的原因。当其中一个完成时,它也会破裂,而我的会完成所有的,不确定哪一个更好。请注意,我的解决方案支持两个以上的ienumerables的组合。@watbywbarif那么你应该在你的需求中解释一下,而不是说你想要一个枚举,其中一个对另一个迭代两个对象。对不起,这只是个例子,如果你看问题,它清楚地说明了几个,从我的助手类中,你可以看到我启用了几个枚举数和每个枚举数的自定义样本数。我也没有说这个解决方案不好,它对我的情况来说是可行的,但在最后,当你比较两个解决方案时,如果两个解决方案都能正常工作,你会考虑一些额外的因素,比如哪个会表现更好,哪个更一般,或者。。。我同意这里不需要像我在解决方案中那样使用OP,因为静态函数的性能更好,代码更短更简单,但这很容易改变。应该怎么办
public IEnumerable<T> Mix<T>(IEnumerable<T> sequenceA, IEnumerable<T> sequenceB, int ratioA, int ratioB)
{
    var etorA = sequenceA.GetEnumerator();
    var etorB = sequenceB.GetEnumerator();
    bool flag = true;

    while(flag)
    {
        flag = false;

        for(int i = 0; i < ratioA && (flag |= etorA.MoveNext()); i++)
            yield return etorA.Current;

        for(int i = 0; i < ratioB && (flag |= etorB.MoveNext()); i++)
            yield return etorB.Current;
    }
}
public IEnumerable<T> Mix<T>(params KeyValuePair<IEnumerable<T>, uint>[] quantifiedSequences)
{
    var sequences = quantifiedSequences.Select(x => new { Etor = x.Key.GetEnumerator(), Quantity = x.Value });
    bool flag = true;

    while(flag)
    {
        foreach (var sequence in sequences)
            for(int i = 0; i < sequence.Quantity && (flag |= sequence.Etor.MoveNext()); i++)
                yield return sequence.Etor.Current;
    }
}