Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
288 views
in Technique[技术] by (71.8m points)

c# - "Turning" an IEnumerable<IEnumerable<T>> 90 degrees

What I'm looking for is a basic operation (Which I'm sure have a name I'm just unaware of atm). I have a matrix like:

{1,2,3}

{A,N,F}

{7,8,9}

which I'd like to mutate into

{1,A,7}

{2,N,8}

{3,F,9}

(The above are only identifiers for objects not real values. The actual objects are of the same type and unordered)

I'd prefer a declarative solution to it but speed is a factor. I'm going to have to turn quite a few tables (100k cells a min) and a slow version would be on the critical path.

However I'm still more interested in a readable solution. I'm looking for alternative solutions to the below. (By alternative I do not mean variations but a different approach)

var  arrays = rows.Select(row => row.ToArray());
var cellCount = arrays.First().Length;
for(var i = 0;i<cellCount;i++){
  yield return GetRow(i,arrays);
}

IEnumerable<T> GetRow(int i,IEnumerable<T[]> rows){
  foreach(var row in rows}{
     yield return row[i]; 
  }
}

Amongst two almost equally readable solutions I'd go for the faster but readability goes before speed

EDIT It will always be a square matrix

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'm a little iffy about this implementation. It has side-effects local to the iterator but looks logically clean to me. This assumes each sequence is the same length but should work for any. You can think of it as a variable length Zip() method. It should perform better than the other linked LINQ solutions found in the other answers as it only uses the minimum operations needed to work. Probably even better without the use of LINQ. Might even be considered optimal.

public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source)
{
    if (source == null) throw new ArgumentNullException("source");
    var enumerators = source.Select(x => x.GetEnumerator()).ToArray();
    try
    {
        while (enumerators.All(x => x.MoveNext()))
        {
            yield return enumerators.Select(x => x.Current).ToArray();
        }
    }
    finally
    {
        foreach (var enumerator in enumerators)
            enumerator.Dispose();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...