简体   繁体   中英

convert 3 dimensional array to a 2 dimensional array

I have this byte array:

byte[,,] somedata = new byte[100,150,3];
~somedata is now populated by an external input.

I want to use the values in just this:

byte[,] useThisDataOnly = new byte[100,150];

Presently, I use this:

foreach (int x=0,x< 100; x++)
{
    foreach (int y=0,y< 150; y++)
    {
       useThisDataOnly [x,y] = somedata[x,y,0];
    }
}

Is there a quicker way to do this at all?

Also, I am going to flatten this useThisDataOnly (as I heard it is quicker to manipulate with).

Any suggestions?

The difficulty you have with optimising this is that the bytes that you want to leave out are in the most "rapidly moving" index.

What I mean by that is: If you assign consecutive numbers to each array element like so:

byte[,,] source = new byte[100, 150, 3];

for (int i = 0, n = 0; i < 100; ++i)
    for (int j = 0; j < 150; ++j)
        for (int k = 0; k < 3; ++k, ++n)
            source[i, j, k] = unchecked ((byte)n);

If you printed out the contents in flattened order, you'd get 0..255 repeating.

Then you exclude the final dimension:

for (int i = 0; i < 100; ++i)
    for (int j = 0; j < 150; ++j)
        dest[i, j] = source[i, j, 0];

If you print the result out in flattened order, you'll get:

0, 3, 6, 9, 12, 15, ...

So you can see that in order to transform the input to the output you need to take every third byte, and unfortunately there is no quick way to do that.

However, if you were able to ask for the array to be created with the index to be omitted first:

byte[,,] source = new byte[3, 100, 150];

then you would be able to use Buffer.BlockCopy() .

I guess this isn't an option - if not, the hand-coded loop is probably the quickest you'll be able to do it without resorting to unsafe code.

Unsafe code

Here's how you can do it using unsafe code and pointers. This might not even make it faster, so before choosing to do it like this you need to (a) be sure that doing the simple way is really too slow and (b) do some careful timings of a release build using Stopwatch to ensure that it really is worth using unsafe code.

Also be aware of the drawbacks of using unsafe code! Unsafe code requires elevated permissions and can cause your program to crash with low-level C++-style wild pointer errors!

using System;
using System.Diagnostics;

namespace Demo
{
    internal static class Program
    {
        static void Main()
        {
            byte[,,] source = new byte[100, 150, 3];

            for (int i = 0, n = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    for (int k = 0; k < 3; ++k, ++n)
                        source[i, j, k] = unchecked ((byte)n);

            byte[,] dest1 = new byte[100, 150];
            byte[,] dest2 = new byte[100, 150];

            for (int i = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    dest1[i, j] = source[i, j, 0];

            unsafe
            {
                fixed (byte* sp = source)
                fixed (byte* dp = dest2)
                {
                    byte* q = dp;
                    byte* p = sp;

                    for (int i = 0; i < 100*150; ++i)
                    {
                        *q++ = *p;
                        p += 3;
                    }
                }
            }

            for (int i = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    Trace.Assert(dest1[i, j] == dest2[i, j], "Arrays should be identical");
        }
    }
}

I personally don't think that it will be too slow using the simple, safe loop anyway, but now at least you have some code to try out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM