4

Would anyone be able to advise if there's a better way to copy multiple arrays into a single array? The resulting array must have the elements in the same order such as arrayOne values first then arraySecond values next etc.

Following is a mockup of what I'm currently executing which working as expected. Looking for a smarter way of doing this.

// Initialise the first array.
string[] arrayOne = new string[5];
arrayOne[0] = "arrayOneValue[0]";
arrayOne[1] = "arrayOneValue[1]";
arrayOne[2] = "arrayOneValue[2]";
arrayOne[3] = "arrayOneValue[3]";
arrayOne[4] = "arrayOneValue[4]";

// Initialise the second array.
string[] arrayTwo = new string[6];
arrayTwo[0] = "arrayTwoValue[0]";
arrayTwo[1] = "arrayTwoValue[1]";
arrayTwo[2] = "arrayTwoValue[2]";
arrayTwo[3] = "arrayTwoValue[3]";
arrayTwo[4] = "arrayTwoValue[4]";
arrayTwo[5] = "arrayTwoValue[5]";

// Initialise the third array.
string[] arrayThree = new string[3];
arrayThree[0] = "arrayThreeValue[0]";
arrayThree[1] = "arrayThreeValue[1]";
arrayThree[2] = "arrayThreeValue[2]";

// string[] arrayN = new string[n]
//.
//.
//.

// Initialise the target array.
string[] finalArray = new string[arrayOne.Length + arrayTwo.Length + arrayThree.Length];
// ArrayN - string[] finalArray = new string[arrayOne.Length + arrayTwo.Length + arrayThree.Length + arrayN.Length];

// Copy/merge the three arrays into the target array.
Array.Copy(arrayOne, 0, finalArray, 0, arrayOne.Length);
Array.Copy(arrayTwo, 0, finalArray, arrayOne.Length, arrayTwo.Length);
Array.Copy(arrayThree, 0, finalArray, (arrayOne.Length + arrayTwo.Length), arrayThree.Length);
//.
//.
//.
//.
// ArrayN - Array.Copy(arrayN, 0, finalArray, (arrayOne.Length + arrayTwo.Length + arrayN), arrayN.Length) ?;

As you can see for arrayN the code can get longer. I have a maximum of 5 arrays I'm trying to copy into one array, therefore, it's manageable. I'm using this technique as part of a WebAPI where a collection of oracle parameter objects are consolidated based on business rules to be passed to several Oracle stored procedures. Any advise here is appreciated. Thanks in advance. Result

Console output 
/*--- Destination array -
arrayOneValue[0]
arrayOneValue[1]
arrayOneValue[2]
arrayOneValue[3]
arrayOneValue[4]
arrayTwoValue[0]
arrayTwoValue[1]
arrayTwoValue[2]
arrayTwoValue[3]
arrayTwoValue[4]
arrayTwoValue[5]
arrayThreeValue[0]
arrayThreeValue[1]
arrayThreeValue[2]*/

6 Answers 6

15

You can just use LINQ .Concat so that you don't need manually take care of arrays lengths and offsets:

var finalArray = arrayOne.Concat(arrayTwo).Concat(arrayThree).ToArray();

It may be little less performant than using Array.Copy, but this code is much more readable, maintainable and error-safe, which is more important.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Elegant solution. I've ended up going with this approach.
You will call 100 times Concat if you have 100 array.
@JoeHuang You are right. It definitely needs a more generic solution, if the number of arrays is arbitrary (and there are good solutions in other answers). Though, it works well for the OP's case when they "have a maximum of 5 arrays"
10

By creating a big array up front, then using Array.Copy, we can achieve very reasonable speeds for concatenating, even with a very large number of arrays:

public static T[] ConcatArrays<T>(params T[][] p)
{
    var position = 0;
    var outputArray = new T[p.Sum(a => a.Length)];
    foreach (var curr in p)
    {
        Array.Copy(curr, 0, outputArray, position, curr.Length);
        position += curr.Length;
    }
    return outputArray;
}

So, now we can either:

string bigArray = ConcatArrays(arrayOne, arrayTwo, arrayThree)

or

string[][] arrays = new[]{arrayOne, arrayTwo, arrayThree};
string bigArray = ConcatArrays(arrays);

1 Comment

Interesting, Thanks, best of both what BurnsBA was concerned about and Yeldar Kurmangaliyev's solution. I'll give this a go at some stage.
3
var one =  new [] { arrayOne, arrayTwo, arrayThree }.SelectMany(x => x);

Comments

2

You can put your input arrays in a collection and iterate over them. I only mention this because this may be more efficient than using LINQ. It depends on the data you're dealing with, but probably not enough to make a difference.

In the code below, on my machine, LINQ takes 9000-13000 ticks (one tick = 100 ns) while calling Array.Copy is ~500 ticks.

public static void Benchmark1()
{
    var arr1 = Enumerable.Range(1,10000).ToArray();
    var arr2 = Enumerable.Range(10001,20000).ToArray();
    var arr3 = Enumerable.Range(20001,30000).ToArray();
    var arr4 = Enumerable.Range(30001,40000).ToArray();

    var sw = Stopwatch.StartNew();
    var result = arr1.Concat(arr2).Concat(arr3).Concat(arr4).ToArray();
    sw.Stop();
    Console.WriteLine($"Elpased ticks: {sw.ElapsedTicks}");
}

public static void Benchmark2()
{
    var arr1 = Enumerable.Range(1,10000).ToArray();
    var arr2 = Enumerable.Range(10001,20000).ToArray();
    var arr3 = Enumerable.Range(20001,30000).ToArray();
    var arr4 = Enumerable.Range(30001,40000).ToArray();

    var arrays = new List<int[]>() {arr1, arr2, arr3, arr4};

    var sw = Stopwatch.StartNew();

    int finalLen = 0;
    foreach (var arr in arrays)
    {
        finalLen += arr.Length;
    }

    var result = new int[finalLen];
    int currentPosition = 0;

    foreach (var arr in arrays)
    {
        Array.Copy(arr, 0, result, currentPosition, arr.Length);
        currentPosition += arr.Length;
    }

    sw.Stop();
    Console.WriteLine($"Elpased ticks: {sw.ElapsedTicks}");
}

1 Comment

Thanks. Great information! Definitely, something to consider for multiple occurrences, and larger arrays. In my use case time wasted is negligible but will keep in mind.
0

Do you have to use arrays? Use lists and AddRange(). If you need to have an array eventually then just call ToArray() in the end.

1 Comment

Thanks, this actually is a possibility. Bit more code refactoring but could be worth it.
0

In C# 12 they introduced the spread operator (..) which can do this for you. See Collection Expressions. Here is how it looks as per Microsoft.

int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[] single = [.. row0, .. row1, .. row2];
foreach (var element in single)
{
    Console.Write($"{element}, ");
}
// output:
// 1, 2, 3, 4, 5, 6, 7, 8, 9,

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.