UIlrvnd
UIlrvnd

Reputation: 786

Most efficient way to merge collections preserving order?

I have 3 channels:

byte[] Red;
byte[] Green;
byte[] Blue;

I need to copy all the values from them into a byte[Red.Length+Green.Length+Blue.Length] PA, so that:

PA[0] = Red[0];
PA[1] = Green[0];
PA[2] = Blue[0];
PA[3] = Red[1];
/// and so on

Here is an example with the above arrays:

byte[] Red = new byte[255];
byte[] Green = new byte[255];
byte[] Blue = new byte[255];
byte[] PA = new byte[Red.Length + Green.Length + Blue.Length];
for (int i = 0; i != 255; ++i)
{
    PA[i*3 + 0] = Red[i];
    PA[i*3 + 1] = Green[i];
    PA[i*3 + 2] = Blue[i];
}

I'm assuming that the collections to be merged are of equal sizes and that they do have some order amongst themselves e.g. [0] = Red, [1]=Green, etc. that has to be preserved for the items in the "merged" collection.

What is the most efficient way to do this in C#? The collections do not have to be arrays nor the items bytes (although collection types that accept bytes would be appreciated).

Upvotes: 3

Views: 254

Answers (3)

Guffa
Guffa

Reputation: 700552

I tried to make a more efficent way by using pointers:

unsafe {
  fixed (byte* red = Red, green = Green, blue = Blue, pa = PA2) {
    byte* r = red, g = green, b = blue, p = pa;
    for (int i = 0; i < 255; i++) {
      *p = *r; p++; r++;
      *p = *g; p++; g++;
      *p = *b; p++; b++;
    }
  }
}

In x86 mode this is about twice as fast, but in x64 mode there is no difference.

In conclusion, the code that you have is already fast enough for most applications. If you need it to be really fast you can optimise it a bit, but not much.

Upvotes: 5

MarcinJuraszek
MarcinJuraszek

Reputation: 125640

I would try avoiding 3*i multiplication:

byte[] Red = new byte[255];
byte[] Green = new byte[255];
byte[] Blue = new byte[255];
int newSize = Red.Length + Green.Length + Blue.Length;
byte[] PA = new byte[newSize];
for (int i = 0; i < newSize; i += 3)
{
    PA[i + 0] = Red[i];
    PA[i + 1] = Green[i];
    PA[i + 2] = Blue[i];
}

Edit

Or even something like that:

for (int i = 0, j = 0; i < 255; i++)
{
    PA[j++] = Red[i];
    PA[j++] = Green[i];
    PA[j++] = Blue[i];
}

(Suggested by Wiktor)

Upvotes: 5

Tigran
Tigran

Reputation: 62276

Efficiency is a thin decisional layer, but from the performance perspective, I would say that you already do it in efficient way.

//allocate immediately memory need, so more shrinking of memory will happen 
byte[] PA = new byte[Red.Length + Green.Length + Blue.Length]; 

//use for loop, that normally equals to foreach in some cases is faster
for (int i = 0; i != 255; ++i)
{
    PA[i + 0] = Red[i];
    PA[i + 1] = Green[i];
    PA[i + 2] = Blue[i];
}

Upvotes: 2

Related Questions