edgarmtze
edgarmtze

Reputation: 25048

matrix to array c#

Which would be the most efficient way to convert a squared matrix like

  1 2 3 
  4 5 6
  7 8 9 

into

[1 2 3 4 5 6 7 8 9]

in c#

I was doing

int[,] array2D = new int[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int[] array1D = new int[9];
int ci=0;

 for (int i = 0; i < 3; i++)
 {
      for (int j = 0; j < 3; j++)
      {
            array1D[ci++] = array2D[i, j]);
      }
 }

Upvotes: 6

Views: 15613

Answers (4)

sakra
sakra

Reputation: 65781

Alternate solution using Buffer.BlockCopy:

int[,] array2D = new int[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int[] array1D = new int[ array2D.Length ];
Buffer.BlockCopy(array2D, 0, array1D, 0, array1D.Length * sizeof(int));

Upvotes: 1

Steve Cooper
Steve Cooper

Reputation: 21480

You're always better off allocating the complete result array in one hit, then copying the data in.

You should find the total size like this;

var size = arrays.Sum(a=> a.Length);
var result = new int[size];

And then copy the arrays using Array.CopyTo, instead of looping yourself;

var cursor = 0;
foreach(var a in arrays) {
   a.CopyTo(result, cursor);
   cursor += a.Length;    
}

Array.CopyTo will be faster than your own loop; at least, not slower. It will probably use C's memcpy function internally to do a low-level block copy. This is as efficient as you can be.

Upvotes: 0

jeroenh
jeroenh

Reputation: 26782

As Jeff said, LINQ makes this trivial. OfType<>() should generally be a little faster than Cast<> though:

array1D = array2D.OfType<int>().ToArray();

The implementation of OfType<> however will still suffer from boxing/unboxing penalties, as @phoog mentioned.

Just for the fun of it, if you want a fast LINQ-based solution (avoiding the cost of boxing) you could use this small extension method:

static class LinqEx
{
    public static IEnumerable<T> Flatten<T>(this T[,] matrix)
    {
        foreach (var item in matrix) yield return item;
    }
}

Or this, based on Jeff's 2nd solution:

    public static IEnumerable<T> Flatten<T>(this T[,] matrix)
    {
        var rows = matrix.GetLength(0);
        var cols = matrix.GetLength(1);
        for (var i = 0; i < rows;i++ )
        {
            for (var j = 0; j < cols; j++ )
                yield return matrix[i, j];
        }
    }

usage:

 int[,] array2D = new int[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };  
 int[] array1D = array2D.Flatten().ToArray();

I didn't fully profile this but I expect this will get you much better performance than the built-in options based on LINQ/IEnumerable. Jeff's second solution will however always be the fasted, it seems.

Upvotes: 1

Jeff Mercado
Jeff Mercado

Reputation: 134841

LINQ makes this trivial.

int[,] array2d = ...;
var array1d = array2d.Cast<int>().ToArray();

Otherwise, your way is adequate but could be generalized:

int[,] array2d = ...;
var rows = array2d.GetLength(0);
var cols = array2d.GetLength(1);
var array1d = new int[rows * cols];
var current = 0;
for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < cols; j++)
    {
        array1d[current++] = array2d[i, j];
    }
}

Or even:

int[,] array2d = ...;
var array1d = new int[array2d.GetLength(0) * array2d.GetLength(1)];
var current = 0;
foreach (var value in array2d)
{
    array1d[current++] = value;
}

Upvotes: 9

Related Questions