How to reshape an Array in c#
This seems to work fine, because the array is already in the right shape in memory:
var a = new byte[2, 2, 2] { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
var b = new byte[2 * 2, 2];
//sizeof(byte) is obviously 1 here, but I put it there for documentation
Buffer.BlockCopy(a, 0, b, 0, a.Length * sizeof(byte));
For those interested: As for what to do if you really want to transpose a 2D array into 1D:
byte[,] a = {
{1, 2},
{3, 4},
{5, 6},
};
var b = new byte[a.GetLength(1) * a.GetLength(0)]; //Transpose
const int R_STRIDE1 = 8; //Tune this for your CPU
const int C_STRIDE1 = 8; //Tune this for your CPU
//You should hoist the calls to GetLength() out of the loop unlike what I do here
for (int r1 = 0; r1 < a.GetLength(0); r1 += R_STRIDE1)
for (int c1 = 0; c1 < a.GetLength(1); c1 += C_STRIDE1)
for (int r2 = 0; r2 < R_STRIDE1; r2++)
for (int c2 = 0; c2 < C_STRIDE1; c2++)
{
var r = r1 + r2;
var c = c1 + c2;
if (r < a.GetLength(0) && c < a.GetLength(1))
b[c * a.GetLength(0) + r] = a[r, c];
}
This should take advantage of caching in the CPU. I have only performed limited testing on this -- it could still be slow. Try tweaking it if it is.
You can (somewhat non-trivially) extend this to a 3D array.
Buffer.BlockCopy
will do it. At least, it works in this simple test.
byte[, ,] src = new byte[10, 10, 3];
byte[,] dest = new byte[100, 3];
List<byte> srcList = new List<byte>();
Random rnd = new Random();
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 10; ++j)
{
for (int k = 0; k < 3; ++k)
{
byte b = (byte)rnd.Next();
src[i, j, k] = b;
srcList.Add(b);
}
}
}
Buffer.BlockCopy(src, 0, dest, 0, 300);
List<byte> destList = new List<byte>();
for (int i = 0; i < 100; ++i)
{
for (int j = 0; j < 3; ++j)
{
destList.Add(dest[i, j]);
}
}
// See if they're in the same order
for (int i = 0; i < srcList.Count; ++i)
{
Console.WriteLine("{0,3:N0} - {1,3:N0}", srcList[i], destList[i]);
if (srcList[i] != destList[i])
{
Console.WriteLine("ERROR!");
}
}
That said, I wouldn't use Buffer.BlockCopy
in this way unless I was absolutely sure that there weren't odd cases with padding issues, etc. And although Buffer.BlockCopy
is certainly faster than the equivalent explicit loop, it shouldn't materially affect the runtime of your program. Unless you're doing this conversion inside a piece of code that's called very, very often ... in which case you have bigger problems.
I would suggest writing the explicit loop.