网格化IEnumerable <t>列在一起</t>

时间:2014-02-26 09:51:47

标签: c# linq

我正在寻找一种最有效的方法来在IEnumerable<T> A中的每一行之前对IEnumerable<T> B中的所有行进行网格划分。

  

例如:

     

A = {A,B}

     

B = {1,2,3}

     

网格划分后:

     

B = {A,1,B,2,A,3}

6 个答案:

答案 0 :(得分:7)

没有简单的解决方案,但这样的事情可能有效。模数运算符在这里非常重要,可以用较少的项重复列表中的结果。

public static List<object> Mesh<T1, T2>(IEnumerable<T1> s1, IEnumerable<T2> s2)
{
     T1[] array1 = s1.ToArray();
     T2[] array2 = s2.ToArray();
     int length1 = array1.Length;
     int length2 = array2.Length;
     int maxLength = Math.Max(length1, length2);
     List<object> result = new List<object>();
     for (int i = 0; i < maxLength; i++)
     {
          result.Add(array1[i % length1]);
          result.Add(array2[i % length2]);
     }
     return result.
}

答案 1 :(得分:2)

该解决方案直接使用IEnumerable参数而不初始化它们,并返回IEnumerable。

public IEnumerable<object> Mesh<S,T>(IEnumerable<S> items1, IEnumerable<T> items2){
    bool items1Empty;
    bool items2Empty;
    bool items1Finished = items1Empty = ValidateParameter(items1, "items1");
    bool items2Finished = items2Empty = ValidateParameter(items2, "items2");

    using(var items1Enumerator = items1.GetEnumerator()){
        using(var items2Enumerator = items2.GetEnumerator()){
            while(true){
                MoveNext(items1Enumerator, ref items1Finished);
                MoveNext(items2Enumerator, ref items2Finished);

                if(items1Finished && items2Finished)
                    break;

                if(!items1Empty)
                    yield return items1Enumerator.Current;

                if(!items2Empty)
                    yield return items2Enumerator.Current;
            }
        }
    }
}

private bool ValidateParameter<T>(IEnumerable<T> parameter, string parameterName){
    if(parameter == null)
        throw new ArgumentNullException(parameterName);
    return !parameter.Any();
}

private void MoveNext(IEnumerator enumerator, ref bool finished){
    if(!enumerator.MoveNext()){
        enumerator.Reset();
        enumerator.MoveNext();
        finished = true;
    }
}

答案 2 :(得分:0)

试试这个,我的第一个猜测

for(int countA = 0, countB = 0; countA < A.Length; countA ++, countB++)
{
    if(countB >= B.Length)
    {
        countB = 0;
    }

    newList.Add(A[countA]);
    newList.Add(B[countB]);
}

答案 3 :(得分:0)

我也想参加派对!由于我非常喜欢LINQ,让我们考虑以下LINQ解决方案(确定它不是那么有效,但是为了好玩):

public static void Main()
{
    var a = new[] {1, 2, 3};
    var b = new[] {'a', 'b'};

    var joined = a.Join(
        b, 
        x => Array.IndexOf(a, x) % b.Length, 
        y => Array.IndexOf(b, y) % a.Length, 
        (x, y) => new object[]{ x, y }
    );

    var flat = joined.SelectMany(x => x);

    Console.Write(string.Join(", ", flat));
}

答案 4 :(得分:0)

另一种方法

public static IEnumerable<T> Mesh<T>(this IEnumerable<T> source, params IEnumerable<T>[] others)
{
    var enumerators = new[] { source.GetEnumerator() }.Concat(others.Select(o => o.GetEnumerator())).ToList();

    var finishes = new bool[enumerators.Count];
    var allFinished = false;
    while (!allFinished)
    {
         allFinsihed = true;
         for (var i = 0; i < enumerators.Count; i++)
         {
             IEnumerator<T> enumerator = enumerators[i];
             if (!enumerator.MoveNext())
             {
                 finishes[i] = true;
                 enumerator.Reset();
                 enumerator.MoveNext(); // Not sure, if we need it here, Reset says: BEFORE the first element
             }

             yield return enumerator.Current;
             if (!finishes[i])
             {
                allFinished = false;
             }
         }
     }
 }

答案 5 :(得分:0)

您可以编写自己的扩展名以提供更大的灵活性。

注意:此答案不会分配大量不必要的内存,并且只列举所有序列一次。

我已经参与了参数检查。

public static IEnumerable<T> Mesh<T>(
    this IEnumerable<T> source,
    params IEnumerable<T>[] others)
{
    if (others.LongLength == 0L)
    {
        foreach (var t in source)
        {
            yield return t;
        }

        yield break;
    }

    var nullCheck = Array.FindIndex(others, e => e == null);
    if (nullCheck >= 0)
    {
        throw new ArgumentNullException(string.Format(
            "Parameter {0} is null, this is not supported.",
            ++nullCheck),
            (Exception)null);
    }

    var enumerators = new[] { source.GetEnumerator() }
        .Concat(others.Select(o => o.GetEnumerator())).ToList();

    try
    {
        var finishes = new bool[enumerators.Count];
        var allFinished = false;
        while (!allFinished)
        {
            allFinsihed = true;
            for (var i = 0; i < enumerators.Count; i++)
            {
                if (finishes[i])
                {
                    continue;
                }

                if (enumerators[i].MoveNext())
                {
                        yield return enumerators[i].Current;
                        allFinished = false;
                        continue;
                }

                finishes[i] = true;
            }
        }
    }
    finally
    {
        foreach (var enumerator in enumerators)
        {
            enumerator.Dispose();
        }
    }   
}

只要项目具有相同的类型,这将允许您“网格化”任意数量的锯齿状序列。 e.g。

var a = new[] { 'a', 'b', 'c' };
var b = new[] { '1', '2', '3' };
var c = new[] { 'x', 'y' };
var d = new[] { '7', '8', '9', '0' };

var meshed = a.Mesh(b, c, d);

会产生

{ 'a', '1', 'x', '7', 'b', '2', 'y', '8', 'c', '3', '9', '0' }

如果你想混合你可以做的类型

var a = new[] { 'a', 'b', 'c' };
var b = new[] { 1, 2, 3 };

var meshed = a.Cast<object>().Mesh(b.Cast<object>);

产生类似的东西,

{ ('a'), (1), ('b'), (2), ('c'), (3) }