0

I have List which contains IEnumerable objects :

List<IEnumerable> enumerables = new List<IEnumerable>();

There can be any number of IEnumerable objects, but every IEnumerable object have the same size as another objects.
Imagine I have sort of this :

[10,20,30],[40,50,60],[70,80,90]

I need to get elements from this List in next order as if that matrix is transposed:

[10,40,70],[20,50,80],[30,60,90]

How can i achieve this?

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179

2 Answers2

0

What you want is a version of Enumerable.Zip that works on 3 enumerables instead of just 2. It just so happens I wrote an extension method for this some time back:

public static IEnumerable<TResult> Zip<TFirst,TSecond,TThird,TResult>(this IEnumerable<TFirst> items1, IEnumerable<TSecond> items2, IEnumerable<TThird> items3, Func<TFirst,TSecond,TThird,TResult> selector)
{
    using (IEnumerator<TFirst> enumerator1 = items1.GetEnumerator())
    using (IEnumerator<TSecond> enumerator2 = items2.GetEnumerator())
    using (IEnumerator<TThird> enumerator3 = items3.GetEnumerator())
    {
        while (enumerator1.MoveNext() && enumerator2.MoveNext() && enumerator3.MoveNext())
        {
            yield return selector(enumerator1.Current, enumerator2.Current, enumerator3.Current);
        }
    }
}

You'd call it like:

enumerables[0].Zip(enumerables[1], enumerables[2], (a, b, c) => new[] { a, b, c }).ToList();
itsme86
  • 19,266
  • 4
  • 41
  • 57
0

I think what you want to do is pivot the IEnumerables in the List. I have a generic version that works with IEnumerable<IEnumerable<T>> that probably has more overhead than a specific List<IEnumerable<T>> would have:

// Pivot IEnumerable<IEnumerable<T>> by grouping matching positions of each sub-IEnumerable<T>
// itemGroups - source data
public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> itemGroups) =>
    itemGroups.Select(g => g.Select((item, i) => (item, i)))
              .SelectMany(g => g)
              .GroupBy(ii => ii.i, si => si.item);

Here is an extension method that uses explicit enumerators to be more efficient:

public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> src) {
    var enums = src.Select(ie => ie.GetEnumerator()).ToList();
    var initialMoveNext = Enumerable.Range(0, enums.Count).Select(n => true).ToList();

    for (; ; ) {
        var moveNext = initialMoveNext.ToArray(); // initialize to all true
        var hasMore = false;

        for (int j1 = 0; j1 < enums.Count; ++j1)
            if (moveNext[j1]) {
                moveNext[j1] = enums[j1].MoveNext();
                hasMore = hasMore || moveNext[j1];
            }

        if (!hasMore)
            break;

        IEnumerable<T> subEnum() {
            for (int j1 = 0; j1 < enums.Count; ++j1) {
                if (moveNext[j1])
                    yield return enums[j1].Current;
            }
        }

        yield return subEnum();
    }

    for (int j1 = 0; j1 < enums.Count; ++j1)
        enums[j1].Dispose();
}
NetMage
  • 26,163
  • 3
  • 34
  • 55