How To Combine Two Arrays Into One In C#

How To Combine Two Arrays Into One Banner

Introduction

If you have two arrays and need to combine them into one array in C#, then there are many built-in options to use like Concat, CopyTo, AddRange, and BlockCopy. Some of these produce a new array or reuse an existing array. Most of these are one line of code but we'll examine the conciseness of the code. I'll also take a look at the performance and how each of these methods scales.

Video With Examples

Summary Table

Analysis TypeEnumerable ConcatArray CopyToList AddRangeBuffer BlockCopy
Rank1234
.NET Framework Version Available>= .NET 3.5>= .NET 1.1>= .NET 2.0>= .NET 1.1
Lines Of Code1546
Duplicates RemovedNoNoNoNo
Speed Test14769ms15608ms28993msN/A
Value Type Speed Test7172ms7240ms12272ms7123ms
LimitationsNoneNoneNoneOnly Value Types Supported

Combine Two Arrays Into One With The Enumerable Concat Method

Enumerable Concat Chart

The concat method combines two sequences. This does not remove the duplicates from the two arrays. These sequences can be of any of the collection types and don't just apply to arrays. So you could combine lists as well for example. Since this is using deferred execution which means that the action is not applied until it is needed which could improve performance.

The name also makes it easy to read and concat is also used in Excel to combine different cells so the name works well in this case as well.

There is also wide support for this method because it was released in .NET 3.5 so it's been around since 2007. You most likely won't have to check which version of .NET, it should be there.

This method will combine the second array with the first. So in the output, you'll see the first array's items followed by the second array's items. Let's see this in action by an example.

The Enumerable Concat Method Video Example

The Enumerable Concat Method Code Example

Enumerable Concat Syntax Image

This code shows different arrays of the different types being combined into one. Since concat returns an IEnumerable object, we need to apply the ToArray to convert the IEnumerable to an array type. There is no issue in applying this method to different types.

The concat method takes up one line of code. It is great that it is compact.

//Create two different arrays of string for different exercises
string[] stringArray1 = new string[] { "Push-ups", "Squats", "Lunges", "Crunches", "Burpees" };
string[] stringArray2 = new string[] { "Deadlifts", "Bench press", "Pull-ups", "Planks", "Jumping jacks" };

//Create two different arrays of int 
int[] intArray1 = new int[] { 3, 7, 11, 19, 23 };
int[] intArray2 = new int[] { 2, 5, 13, 17, 29 };

//Create two different arrays of double
double[] doubleArray1 = new double[] { 1.234, 4.567, 7.890, 10.111, 12.131 };
double[] doubleArray2 = new double[] { 2.345, 5.678, 9.012, 11.113, 13.141 };

//Create two different arrays of bool
bool[] boolArray1 = new bool[] { true, false,s true, true, false };
bool[] boolArray2 = new bool[] { false, true, false, false, true };

//Create two different arrays of float
float[] floatArray1 = new float[] { 1.23f, 4.56f, 7.89f, 10.11f, 12.13f };
float[] floatArray2 = new float[] { 2.34f, 5.67f, 8.91f, 11.12f, 13.14f };

//Combined array method
string[] combinedStringArray = CombineTwoArraysIntoOne<string>(stringArray1, stringArray2);
int[] combinedIntArray = CombineTwoArraysIntoOne<int>(intArray1, intArray2);
double[] combinedDoubleArray = CombineTwoArraysIntoOne<double>(doubleArray1, doubleArray2);
bool[] combinedBoolArray = CombineTwoArraysIntoOne<bool>(boolArray1, boolArray2);
float[] combinedFloatArray = CombineTwoArraysIntoOne<float>(floatArray1, floatArray2);

//Print out each array
PrintArray<string>(combinedStringArray);
PrintArray<int>(combinedIntArray);
PrintArray<double>(combinedDoubleArray);
PrintArray<bool>(combinedBoolArray);
PrintArray<float>(combinedFloatArray);


T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    return array1.Concat(array2).ToArray();//Use Enumerable Concat to combine array1 and array2 together
}

void PrintArray<T>(T[] array)
{
    int index = 0;
    foreach (T item in array)//Loop through each item in the array
    {
        Console.WriteLine($"[{index++}] = {item}");//Print array item to the screen
    }
    Console.WriteLine();
    Console.WriteLine();
}
Enumerable Concat Code Example Output
stringintdoubleboolfloat
[0] = Push-ups[0] = 3[0] = 1.234[0] = True[0] = 1.23
[1] = Squats[1] = 7[1] = 4.567[1] = False[1] = 4.56
[2] = Lunges[2] = 11[2] = 7.89[2] = True[2] = 7.89
[3] = Crunches[3] = 19[3] = 10.111[3] = True[3] = 10.11
[4] = Burpees[4] = 23[4] = 12.131[4] = False[4] = 12.13
[5] = Deadlifts[5] = 2[5] = 2.345[5] = False[5] = 2.34
[6] = Bench press[6] = 5[6] = 5.678[6] = True[6] = 5.67
[7] = Pull-ups[7] = 13[7] = 9.012[7] = False[7] = 8.91
[8] = Planks[8] = 17[8] = 11.113[8] = False[8] = 11.12
[9] = Jumping jacks[9] = 29[9] = 13.141[9] = True[9] = 13.14

Combine Two Arrays Into One With The Array CopyTo Method

Array CopyTo Chart

This method copies the source array to the destination array at the starting index. Because we are combining two arrays into one we need to use two CopyTo operations for each source array.

Array CopyTo is a very old method. It has been around since .NET version 1.1 so it is almost certain that this method will exist in your current version C# application.

The Array CopyTo Method Code Example

This method has a 3 step process. First, an empty array that will hold the two arrays combined. Next, you'll need to copy the first array into an empty array. Then finally copy the second array into the destination array at the start point where the first array ended.

Because of this process, the code is increased in size and there are potentially more contacts of failure than in the previous enumerable concat method. But the name CopyTo makes it easier to read and understand what is going on.

Array CopyTo Syntax Image
//Create two different arrays of string for different exercises
string[] stringArray1 = new string[] { "Bicep curls", "Tricep extensions", "Shoulder press", "Dumbbell rows", "Hammer curls" };
string[] stringArray2 = new string[] { "Leg press", "Calf raises", "Hip thrusts", "Glute bridges", "Step-ups" };

//Create two different arrays of int 
int[] intArray1 = new int[] { 1, 3, 5, 7, 9 };
int[] intArray2 = new int[] { 2, 4, 6, 8, 10 };

//Create two different arrays of double
double[] doubleArray1 = new double[] { 1.23, 3.45, 5.67, 7.89, 9.01 };
double[] doubleArray2 = new double[] { 2.34, 4.56, 6.78, 8.90, 10.12 };

//Create two different arrays of bool
bool[] boolArray1 = new bool[] { true, false, true, true, false };
bool[] boolArray2 = new bool[] { false, true, false, false, true };

//Create two different arrays of float
float[] floatArray1 = new float[] { 1.2f, 3.4f, 5.6f, 7.8f, 9.0f };
float[] floatArray2 = new float[] { 2.3f, 4.5f, 6.7f, 8.9f, 10.1f };

//Combined array method
string[] combinedStringArray = CombineTwoArraysIntoOne<string>(stringArray1, stringArray2);
int[] combinedIntArray = CombineTwoArraysIntoOne<int>(intArray1, intArray2);
double[] combinedDoubleArray = CombineTwoArraysIntoOne<double>(doubleArray1, doubleArray2);
bool[] combinedBoolArray = CombineTwoArraysIntoOne<bool>(boolArray1, boolArray2);
float[] combinedFloatArray = CombineTwoArraysIntoOne<float>(floatArray1, floatArray2);

T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    const int array1StartCopyIndex = 0;//Set the starting index for array1
    T[] destinationArray = new T[array1.Length + array2.Length];//Create a new array that holds the combination
    array1.CopyTo(destinationArray, array1StartCopyIndex);//Copy array1 to the destination array
    array2.CopyTo(destinationArray, array1.Length);//Copy array2 to the destination array starting where array1 left off
    return destinationArray;
}
Array CopyTo Code Example Output
stringintdoubleboolfloat
[0] = Bicep curls[0] = 1[0] = 1.23[0] = True[0] = 1.2
[1] = Tricep extensions[1] = 3[1] = 3.45[1] = False[1] = 3.4
[2] = Shoulder press[2] = 5[2] = 5.67[2] = True[2] = 5.6
[3] = Dumbbell rows[3] = 7[3] = 7.89[3] = True[3] = 7.8
[4] = Hammer curls[4] = 9[4] = 9.01[4] = False[4] = 9
[5] = Leg press[5] = 2[5] = 2.34[5] = False[5] = 2.3
[6] = Calf raises[6] = 4[6] = 4.56[6] = True[6] = 4.5
[7] = Hip thrusts[7] = 6[7] = 6.78[7] = False[7] = 6.7
[8] = Glute bridges[8] = 8[8] = 8.9[8] = False[8] = 8.9
[9] = Step-ups[9] = 10[9] = 10.12[9] = True[9] = 10.1

Combine Two Arrays Into One With The List AddRange Method

List AddRange Chart

Using List may seem like a convoluted way to combine two arrays but it is similar to what initially seems. A list allows us to add the array items to it without knowing how big the arrays are. But there's an optimization step that we can take with lists. We can set the list's initial size to the size of the addition of both array sizes. This means that the list will not increase in size over time. The resizing of an array is an expensive operation and internally a list has an array as its data structure.

This method has had support since .NET 2.0 in 2005 so it is widely available.

The List AddRange Method Code Example

List AddRange Syntax Image

There are three steps to this process. The first step is to create the temporary list, but for this list, we will set the initial size of the combination of sizes of the two arrays. The next step is the add the arrays to the list by the AddRange method. AddRange allows us to add the whole array rather than its elements one by one. The final step is the convert the list to an array by the ToArray method provided in LINQ.

The code takes 4 lines of code which aren't too bad but greater than the one-liners in some of the other methods.

//Create two different arrays of string for different exercises
string[] stringArray1 = new string[] { "Bicycle crunches", "Russian twists", "Leg raises", "Mountain climbers", "Flutter kicks" };
string[] stringArray2 = new string[] { "Lat pulldowns", "Seated rows", "Chin-ups", "Cable curls", "Tricep pushdowns" };

//Create two different arrays of int 
int[] intArray1 = new int[] { 4, 75, 98, 21, 28 };
int[] intArray2 = new int[] { 21, 25, 74, 18, 30 };

//Create two different arrays of double
double[] doubleArray1 = new double[] { 8.81, 1.2, 0.82, 28.81, 3.49 };
double[] doubleArray2 = new double[] { 98.17, 217.1, 819.1, 75.96, 89.18 };

//Create two different arrays of bool
bool[] boolArray1 = new bool[] { true, false, true, false, true };
bool[] boolArray2 = new bool[] { true, true, true, false, false };

//Create two different arrays of float
float[] floatArray1 = new float[] { 5.23f, 89.56f, 53.89f, 89.21f, 86.70f };
float[] floatArray2 = new float[] { 8.34f, 21.67f, 18.91f, 34.12f, 57.14f };

//Combined array method
string[] combinedStringArray = CombineTwoArraysIntoOne<string>(stringArray1, stringArray2);
int[] combinedIntArray = CombineTwoArraysIntoOne<int>(intArray1, intArray2);
double[] combinedDoubleArray = CombineTwoArraysIntoOne<double>(doubleArray1, doubleArray2);
bool[] combinedBoolArray = CombineTwoArraysIntoOne<bool>(boolArray1, boolArray2);
float[] combinedFloatArray = CombineTwoArraysIntoOne<float>(floatArray1, floatArray2);

T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    List<T> list = new List<T>(array1.Length + array2.Length);//create a new list the size of combined arrays
    list.AddRange(array1);//Add array1 to the list
    list.AddRange(array2);//Add array2 to the list
    return list.ToArray();//Convert the list to an array
}
List AddRange Example Code Output
stringintdoubleboolfloat
[0] = Bicycle crunches[0] = 4[0] = 8.81[0] = True[0] = 1.2
[1] = Russian twists[1] = 75[1] = 1.2[1] = False[1] = 3.4
[2] = Leg raises[2] = 98[2] = 0.82[2] = True[2] = 5.6
[3] = Mountain climbers[3] = 21[3] = 28.81[3] = False[3] = 7.8
[4] = Flutter kicks[4] = 28[4] = 3.49[4] = True[4] = 9
[5] = Lat pulldowns[5] = 21[5] = 98.17[5] = True[5] = 2.3
[6] = Seated rows[6] = 25[6] = 217.1[6] = True[6] = 4.5
[7] = Chin-ups[7] = 74[7] = 819.1[7] = True[7] = 6.7
[8] = Cable curls[8] = 18[8] = 75.96[8] = False[8] = 8.9
[9] = Tricep pushdowns[9] = 30[9] = 89.18[9] = False[9] = 10.1

Combine Two Arrays Into One With The Buffer BlockCopy Method

Buffer BlockCopy Chart

The BlockCopy method copies bytes of data at a time and is usually better suited for minute-byte operations. It copies blocks of bytes at a time so that is why we use the size of the method to get the type we're using and then multiply it by the size of the array. BlockCopy does the byte copy on a lower level.

There is a huge downsize to this method. It only lets us copy value types which are int, bool, double, float, etc. So that excludes strings, other reference types, and classes that we may create.

It is available since .NET 1.1 which makes it widely available.

It is slightly more complicated to set up since you need the size of the array in the number of bytes. This means using the size of the method to get the type you using for the array. But this also means you can't use a generic implementation. So you have to create a new function for each type that you're going to use as you'll see below.

Then once you have the size of the arrays in the number of bytes you can give the ranges in the BlockCopy method to copy each one to the new array.

The Buffer BlockCopy Method Code Example

Buffer BlockCopy Syntax Image

As you can see in this example there is no string example because BlockCopy only works with value types and string is a reference type so it won't work with this method. This is a 3-step process. First, the new array is created. Then the sizes of each of the arrays are obtained in bytes by the size of method. Then lastly we can copy the arrays to the new array using the BlockCopy method.

//Create two different arrays of int 
int[] intArray1 = new int[] { 13, 57, 56, 45, 8 };
int[] intArray2 = new int[] { 12, 57, 22, 18, 83 };

//Create two different arrays of double
double[] doubleArray1 = new double[] { 28.05, 41.33, 41.36, 6.18, 3.94 };
double[] doubleArray2 = new double[] { 7.23, 61.09, 16.32, 33.89, 6.31 };

//Create two different arrays of bool
bool[] boolArray1 = new bool[] { false, true, false, false, true };
bool[] boolArray2 = new bool[] { false, false, true, false, true };

//Create two different arrays of float
float[] floatArray1 = new float[] { 16.7f, 19.05f, 45.72f, 4.34f, 1.36f };
float[] floatArray2 = new float[] { 13.28f, 0f, 0.89f, 29.98f, 1.87f };

//Combined array method
int[] combinedIntArray = CombineTwoIntArraysIntoOne(intArray1, intArray2);
double[] combinedDoubleArray = CombineTwoDoubleArraysIntoOne(doubleArray1, doubleArray2);
bool[] combinedBoolArray = CombineTwoBoolArraysIntoOne(boolArray1, boolArray2);
float[] combinedFloatArray = CombineTwoFloatArraysIntoOne(floatArray1, floatArray2);

int[] CombineTwoIntArraysIntoOne(int[] array1, int[] array2)
{
    int[] newArray = new int[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(int);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(int);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

double[] CombineTwoDoubleArraysIntoOne(double[] array1, double[] array2)
{
    double[] newArray = new double[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(double);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(double);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

bool[] CombineTwoBoolArraysIntoOne(bool[] array1, bool[] array2)
{
    bool[] newArray = new bool[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(bool);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(bool);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

float[] CombineTwoFloatArraysIntoOne(float[] array1, float[] array2)
{
    float[] newArray = new float[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(float);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(float);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

Buffer BlockCopy Code Output
intdoubleboolfloat
[0] = 13[0] = 28.05[0] = False[0] = 16.7
[1] = 57[1] = 41.33[1] = True[1] = 19.05
[2] = 56[2] = 41.36[2] = False[2] = 45.72
[3] = 45[3] = 6.18[3] = False[3] = 4.34
[4] = 8[4] = 3.94[4] = True[4] = 1.36
[5] = 12[5] = 7.23[5] = False[5] = 13.28
[6] = 57[6] = 61.09[6] = False[6] = 0
[7] = 22[7] = 16.32[7] = True[7] = 0.89
[8] = 18[8] = 33.89[8] = False[8] = 29.98
[9] = 83[9] = 6.31[9] = True[9] = 1.87

Speed Test

This speed test is an average of 10 tests. Each test will have a loop that calls the test function 100 times. Each test function has 5 million items per array with two arrays per type.

This will thoroughly test these methods across a variety of types so that we can compare.

Enumerable Concat Speed Test Code

void TestMethod(TestArrayDataContainer testArrayDataContainer)
{
    string[] combinedStringArray = CombineTwoArraysIntoOne<string>(testArrayDataContainer.stringData1, testArrayDataContainer.stringData2);
    int[] combinedIntArray = CombineTwoArraysIntoOne<int>(testArrayDataContainer.intData1, testArrayDataContainer.intData2);
    double[] combinedDoubleArray = CombineTwoArraysIntoOne<double>(testArrayDataContainer.doubleData1, testArrayDataContainer.doubleData2);
    bool[] combinedBoolArray = CombineTwoArraysIntoOne<bool>(testArrayDataContainer.boolData1, testArrayDataContainer.boolData2);
    float[] combinedFloatArray = CombineTwoArraysIntoOne<float>(testArrayDataContainer.floatArray1, testArrayDataContainer.floatArray2);
}

T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    return array1.Concat(array2).ToArray();//Use Enumerable Concat to combine array1 and array2 together
}

Array CopyTo Speed Test Code

T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    const int array1StartCopyIndex = 0;//Set the starting index for array1
    T[] destinationArray = new T[array1.Length + array2.Length];//Create a new array that holds the combination
    array1.CopyTo(destinationArray, array1StartCopyIndex);//Copy array1 to the destination array
    array2.CopyTo(destinationArray, array1.Length);//Copy array2 to the destination array starting where array1 left off
    return destinationArray;//return combined array
}

List AddRange Speed Test Code

T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    List<T> list = new List<T>(array1.Length + array2.Length);//create a new list the size of combined arrays
    list.AddRange(array1);//Add array1 to the list
    list.AddRange(array2);//Add array2 to the list
    return list.ToArray();//Convert the list to an array
}

Buffer BlockCopy Speed Test Code

void TestMethod(TestArrayDataContainer testArrayDataContainer)
{
int[] combinedIntArray = CombineTwoIntArraysIntoOne(testArrayDataContainer.intData1, testArrayDataContainer.intData2);
double[] combinedDoubleArray = CombineTwoDoubleArraysIntoOne(testArrayDataContainer.doubleData1, testArrayDataContainer.doubleData2);
bool[] combinedBoolArray = CombineTwoBoolArraysIntoOne(testArrayDataContainer.boolData1, testArrayDataContainer.boolData2);
float[] combinedFloatArray = CombineTwoFloatArraysIntoOne(testArrayDataContainer.floatArray1, testArrayDataContainer.floatArray2);
}

int[] CombineTwoIntArraysIntoOne(int[] array1, int[] array2)
{
    int[] newArray = new int[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(int);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(int);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

double[] CombineTwoDoubleArraysIntoOne(double[] array1, double[] array2)
{
    double[] newArray = new double[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(double);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(double);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

bool[] CombineTwoBoolArraysIntoOne(bool[] array1, bool[] array2)
{
    bool[] newArray = new bool[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(bool);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(bool);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}

float[] CombineTwoFloatArraysIntoOne(float[] array1, float[] array2)
{
    float[] newArray = new float[array1.Length + array2.Length];//Create new array

    int array1Size = array1.Length * sizeof(float);//Get the length of the array by the number of bytes
    int array2Size = array2.Length * sizeof(float);//Get the length of the array by the number of bytes

    Buffer.BlockCopy(array1, 0, newArray, 0, array1Size);//Copy first array to new array
    Buffer.BlockCopy(array2, 0, newArray, array1Size, array2Size);//Copy second array to new array
    return newArray;
}
Enumerable Concat Speed Test Code Output
Test 1: 0m 7s 354ms
Test 2: 0m 7s 198ms
Test 3: 0m 7s 146ms
Test 4: 0m 7s 157ms
Test 5: 0m 7s 122ms
Test 6: 0m 7s 192ms
Test 7: 0m 7s 119ms
Test 8: 0m 7s 176ms
Test 9: 0m 7s 142ms
Test 10: 0m 7s 113ms
Enumerable Concat Average Speed:7172ms, In 10 Tests
Array CopyTo Speed Test Code Output
Test 1: 0m 15s 923ms
Test 2: 0m 16s 48ms
Test 3: 0m 15s 558ms
Test 4: 0m 15s 601ms
Test 5: 0m 15s 442ms
Test 6: 0m 15s 414ms
Test 7: 0m 14s 718ms
Test 8: 0m 15s 390ms
Test 9: 0m 15s 910ms
Test 10: 0m 16s 74ms
Array CopyTo Average Speed:15608ms, In 10 Tests
List AddRange Speed Test Code Output
Test 1: 0m 30s 56ms
Test 2: 0m 29s 22ms
Test 3: 0m 28s 379ms
Test 4: 0m 28s 10ms
Test 5: 0m 29s 84ms
Test 6: 0m 28s 765ms
Test 7: 0m 29s 86ms
Test 8: 0m 29s 3ms
Test 9: 0m 29s 109ms
Test 10: 0m 29s 414ms
List AddRange Average Speed:28993ms, In 10 Tests
Full Enumerable Concat Test Code

using System.Diagnostics;

int numberOfTests = 10;//Number of tests 
int numberOfFunctionCalls = 100;//Number of function calls made per test
int numberOfObjectsToCreate = 5000000;//Number test objects
int lengthOfRandomString = 50;
string testName = "Enumerable Concat";//Test name to print to average

void TestMethod(TestArrayDataContainer testArrayDataContainer)
{
    string[] combinedStringArray = CombineTwoArraysIntoOne<string>(testArrayDataContainer.stringData1, testArrayDataContainer.stringData2);
    int[] combinedIntArray = CombineTwoArraysIntoOne<int>(testArrayDataContainer.intData1, testArrayDataContainer.intData2);
    double[] combinedDoubleArray = CombineTwoArraysIntoOne<double>(testArrayDataContainer.doubleData1, testArrayDataContainer.doubleData2);
    bool[] combinedBoolArray = CombineTwoArraysIntoOne<bool>(testArrayDataContainer.boolData1, testArrayDataContainer.boolData2);
    float[] combinedFloatArray = CombineTwoArraysIntoOne<float>(testArrayDataContainer.floatArray1, testArrayDataContainer.floatArray2);
}

T[] CombineTwoArraysIntoOne<T>(T[] array1, T[] array2)
{
    return array1.Concat(array2).ToArray();//Use Enumerable Concat to combine array1 and array2 together
}

List<double> testSpeedList = new List<double>();
for (int testIndex = 0; testIndex < numberOfTests; testIndex++)
{
    testSpeedList.Add(StartTest(testIndex));
}
Console.WriteLine($"{testName} Average Speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} Tests");

double StartTest(int testIndex)
{
    Stopwatch stopwatch = new Stopwatch();
    string[] testStringData1 = GetStringArrayData();//Generate a random array of strings
    string[] testStringData2 = GetStringArrayData();//Generate a random array of strings
    int[] testIntData1 = GetIntArrayData();//Generate a random array of ints
    int[] testIntData2 = GetIntArrayData();//Generate a random array of ints
    double[] testDoubleData1 = GetDoubleArrayData();//Generate a random array of double
    double[] testDoubleData2 = GetDoubleArrayData();//Generate a random array of double
    bool[] testBoolData1 = GetBoolArrayData();//Generate a random array of bool
    bool[] testBoolData2 = GetBoolArrayData();//Generate a random array of bool
    float[] testFloatData1 = GetFloatArrayData();//Generate a random array of float
    float[] testFloatData2 = GetFloatArrayData();//Generate a random array of float
    TestArrayDataContainer testArrayDataContainer = new TestArrayDataContainer(testStringData1, testStringData2, testIntData1, testIntData2, testDoubleData1, testDoubleData2, testBoolData1, testBoolData2, testFloatData1, testFloatData2);
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        stopwatch.Start();//Start the Stopwatch timer
        TestMethod(testArrayDataContainer);//
        stopwatch.Stop();//Stop the Stopwatch timer
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"Test {testIndex + 1}: {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}

string[] GetStringArrayData()
{
    string[] testData = new string[numberOfObjectsToCreate];
    for (int i = 0; i < numberOfObjectsToCreate; i++)
    {
        string value = GenerateRandomString(lengthOfRandomString);
        testData[i] = value;
    }
    return testData;
}

int[] GetIntArrayData()
{
    Random random = new Random();
    int[] testData = new int[numberOfObjectsToCreate];
    for (int i = 0; i < numberOfObjectsToCreate; i++)
    {
        testData[i] = random.Next(0, numberOfObjectsToCreate);
    }
    return testData;
}

double[] GetDoubleArrayData()
{
    Random random = new Random();
    double[] testData = new double[numberOfObjectsToCreate];
    for (int i = 0; i < numberOfObjectsToCreate; i++)
    {
        testData[i] = random.NextDouble();
    }
    return testData;
}

bool[] GetBoolArrayData()
{
    Random random = new Random();
    bool[] testData = new bool[numberOfObjectsToCreate];
    for (int i = 0; i < numberOfObjectsToCreate; i++)
    {
        testData[i] = (random.Next(0, 1) == 1 ? true : false);
    }
    return testData;
}

float[] GetFloatArrayData()
{
    Random random = new Random();
    float[] testData = new float[numberOfObjectsToCreate];
    for (int i = 0; i < numberOfObjectsToCreate; i++)
    {
        testData[i] = random.NextSingle();
    }
    return testData;
}
string GenerateRandomString(int length)
{
    Random random = new Random();
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}
class TestArrayDataContainer
{
    public string[] stringData1;
    public string[] stringData2;

    public int[] intData1;
    public int[] intData2;

    public double[] doubleData1;
    public double[] doubleData2;

    public bool[] boolData1;
    public bool[] boolData2;

    public float[] floatArray1;
    public float[] floatArray2;

    public TestArrayDataContainer(string[] stringData1, string[] stringData2, int[] intData1, int[] intData2, double[] doubleData1, double[] doubleData2, bool[] boolData1, bool[] boolData2, float[] floatArray1, float[] floatArray2)
    {
        this.stringData1 = stringData1;
        this.stringData2 = stringData2;
        this.intData1 = intData1;
        this.intData2 = intData2;
        this.doubleData1 = doubleData1;
        this.doubleData2 = doubleData2;
        this.boolData1 = boolData1;
        this.boolData2 = boolData2;
        this.floatArray1 = floatArray1;
        this.floatArray2 = floatArray2;
    }
}

Value Type Speed Test

This is the same set of tests as before except the string array test is excluded and it is only value types such as int, float, bool, and double.

Value Type Test Parameters
Test ParametersTotal
Tests10
Function Calls Per Test100
Objects Per Function Call5 Million Per Array
Enumerable Concat Value Type Speed Test Code Output
Test 1: 0m 15s 56ms
Test 2: 0m 15s 40ms
Test 3: 0m 14s 819ms
Test 4: 0m 14s 809ms
Test 5: 0m 14s 625ms
Test 6: 0m 14s 569ms
Test 7: 0m 14s 601ms
Test 8: 0m 14s 837ms
Test 9: 0m 14s 633ms
Test 10: 0m 14s 700ms
Enumerable Concat Average Value Type Type Speed:14769ms, In 10 Tests
Array CopyTo Value Type Speed Test Code Output
Test 1: 0m 7s 158ms
Test 2: 0m 7s 1ms
Test 3: 0m 7s 82ms
Test 4: 0m 7s 149ms
Test 5: 0m 7s 167ms
Test 6: 0m 7s 162ms
Test 7: 0m 7s 92ms
Test 8: 0m 7s 140ms
Test 9: 0m 7s 173ms
Test 10: 0m 7s 97ms
Array CopyTo Average Value Type Speed:7123ms, In 10 Tests
List AddRange Value Type Speed Test Code Output
Test 1: 0m 13s 838ms
Test 2: 0m 13s 189ms
Test 3: 0m 9s 32ms
Test 4: 0m 13s 745ms
Test 5: 0m 12s 546ms
Test 6: 0m 13s 566ms
Test 7: 0m 13s 800ms
Test 8: 0m 8s 452ms
Test 9: 0m 13s 630ms
Test 10: 0m 10s 915ms
List AddRange Average Type Speed:12272ms, In 10 Tests
Buffer Block Value Type Speed Test Code Output
Test 1: 0m 7s 387ms
Test 2: 0m 7s 324ms
Test 3: 0m 7s 106ms
Test 4: 0m 7s 365ms
Test 5: 0m 7s 202ms
Test 6: 0m 7s 318ms
Test 7: 0m 7s 109ms
Test 8: 0m 7s 126ms
Test 9: 0m 7s 289ms
Test 10: 0m 7s 167ms
Buffer BlockCopy Average Value Type Speed:7240ms, In 10 Tests

Conclusion

The best method for copying two arrays into one is the Enumerable Concat method. It is tied with the fastest method and it all fits on one line. There is still wide support from .NET 3.5 and it is easy to read so it is an all-around great method to use for this use case.

The Array CopyTo method is only slightly slower but still pretty fast than the enumerable concat method but it takes up more coding space and setup. The method name is easy to read and has even wider support being from .NET 1.1.

The List AddRange method, I wouldn't recommend using it because it is so slow. it is almost twice as slow as the other methods. It may be convenient to use but avoid using this method for this use case.

Also for Buffer BlockCopy, I can't recommend this either because it only works on reference types. It wouldn't work with strings or the class that you write so it's a big disappointment because it was fast. Another pain with this method is the setup, it takes the longest to set up and it is more method parameters to set up.

Know any other ways to combine two arrays into one array? Let me know in the comments below.

Get Latest Updates