Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ swap columns into rows

Tags:

c#

linq

Is there a fancy LINQ expression that could allow me to do the following in a much more simpler fashion. I have a List<List<double>>, assuming the List are columns in a 2d matrix, I want to swap the list of columns into a list of rows. I have the following obvious solution:

int columns = 5;
var values; // assume initialised as List<List<double>>()

var listOfRows = new List<List<double>>();
for (int i = 0; i < columns ; i++)
{
    List<double> newRow = new List<double>();
    foreach (List<double> value in values)
    {
        newRow.Add(value[i]);
    }
    listOfRows.Add(newRow);
}
like image 205
Seth Avatar asked Aug 05 '11 01:08

Seth


2 Answers

Here's one that works for rectangular (non-ragged) matrices. The C# code here works cut-and-paste into LinqPad, a free, interactive C# programming tool.

I define a postfix operator (that is, an extension method) "Transpose." Use the operator as follows:

    var rand = new Random();

    var xss = new [] {
        new [] {rand.NextDouble(), rand.NextDouble()},
        new [] {rand.NextDouble(), rand.NextDouble()},
        new [] {rand.NextDouble(), rand.NextDouble()},
    };

    xss.Dump("Original");
    xss.Transpose().Dump("Transpose");

resulting in something like this:

Original
0.843094345109116
0.981432441613373

0.649207864724662
0.00594645645746331

0.378864820291691
0.336915332515219


Transpose
0.843094345109116
0.649207864724662
0.378864820291691

0.981432441613373
0.00594645645746331
0.336915332515219

The gist of the implementation of this operator is the following

    public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> xss)
    {
        var heads = xss.Heads();
        var tails = xss.Tails();

        var empt = new List<IEnumerable<T>>();
        if (heads.IsEmpty())
            return empt;
        empt.Add(heads);
        return empt.Concat(tails.Transpose());
    }

Here is the full implementation, with some lines commented out that you can uncomment to monitor how the function works.

void Main()
{
    var rand = new Random();

    var xss = new [] {
        new [] {rand.NextDouble(), rand.NextDouble()},
        new [] {rand.NextDouble(), rand.NextDouble()},
        new [] {rand.NextDouble(), rand.NextDouble()},
    };
    xss.Dump("Original");
    xss.Transpose().Dump("Transpose");
}

public static class Extensions
{
    public static IEnumerable<T> Heads<T>(this IEnumerable<IEnumerable<T>> xss)
    {
        Debug.Assert(xss != null);
        if (xss.Any(xs => xs.IsEmpty()))
            return new List<T>();
        return xss.Select(xs => xs.First());
    }

    public static bool IsEmpty<T>(this IEnumerable<T> xs)
    {
        return xs.Count() == 0;
    }

    public static IEnumerable<IEnumerable<T>> Tails<T>(this IEnumerable<IEnumerable<T>> xss)
    {
        return xss.Select(xs => xs.Skip(1));
    }

    public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> xss)
    {
//      xss.Dump("xss in Transpose");
        var heads = xss.Heads()
//          .Dump("heads in Transpose")
            ;
        var tails = xss.Tails()
//          .Dump("tails in Transpose")
            ;

        var empt = new List<IEnumerable<T>>();
        if (heads.IsEmpty())
            return empt;
        empt.Add(heads);
        return empt.Concat(tails.Transpose())
//          .Dump("empt")
            ;
    }
}
like image 50
Reb.Cabin Avatar answered Oct 06 '22 08:10

Reb.Cabin


var inverted = Enumerable.Range(0, columnCount)
               .Select(index => columnList.Select(list => list[index]));

In short, we enumerate the column index from a range and use it to collect the nth element of each list.

Please note that you'll need to check that every list has the same number of columns.

like image 20
vc 74 Avatar answered Oct 06 '22 07:10

vc 74