0

I ran into an issue and I'm not sure if I'm missing something or if it's just really clunky in C#.

I have a 2D-array (Foo[,]) and what I want to do is to map it to a Bar[,], using nothing but a Func<Foo, Bar>. Basically, what I want is a functor instance for T[,] for any given T.

The "obvious" way is of course to simply build a new array from the ground up, iterating over each column row and column and manually applying the function to ever cell. I would really like to make use of LINQ for this though, because there is no reason whatsoever this should be more complicated than

from cell in matrix
select f(cell)

or the equivalent matrix.Select(f).

I can't help but to think that I can't be first one who wanted to do this, so I wonder if there's something similar built-in, or is my best bet to simply write my own LINQ extensions for 2D arrays?

sara
  • 3,521
  • 14
  • 34

2 Answers2

0

There are no LINQ methods in .Net Framework that work directly with 2d array. The best you can get from built-in code - iterating over all items via non-generic IEnumerable with manual Cast (Why do C# Multidimensional arrays not implement IEnumerable<T>?, Using Linq with 2D array, Select not found)

As solution - write your own extensions or find library.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Writing a bunch of custom LINQ extensions seems like the easiest and cleanest path. Kind of tedious to have to write and maintain that kind of boilerplate code, but oh well. – sara Jul 19 '16 at 16:20
0

Not sure if this is the "best" way (whatever that means), but this works at least. Can easily be extended if you need more LINQ syntax.

public static class Matrix
{
    public static TResult[,] Select<T, TResult>(this T[,] source, Func<T, TResult> f)
    {
        var rows = source.GetLength(0);
        var columns = source.GetLength(1);
        var result = new TResult[rows, columns];

        for (var row = 0; row < rows; row++)
        {
            for (var column = 0; column < columns; column++)
            {
                result[row, column] = f(source[row, column]);
            }
        }

        return result;
    }
}

Tested using the following (rather lack-luster) xunit fact, feel free to point out bugs.

[Fact]
public void MatrixSelect_GivenFunction_MapsMatrix()
{
    var matrix = new[,]
    {
        {true, true},
        {false, true}
    };

    var transformed =
        from cell in matrix
        select cell ? 1 : 0;

    var expected = new[,]
    {
        {1, 1},
        {0, 1}
    };
    Assert.Equal(expected, transformed);
}
sara
  • 3,521
  • 14
  • 34