codex
codex

Reputation: 93

c# A better way to Copy/Merge multiple arrays into one array

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]*/

Upvotes: 3

Views: 20256

Answers (6)

A_Arnold
A_Arnold

Reputation: 4069

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,

Upvotes: 0

jwize
jwize

Reputation: 4165

var one =  new [] { arrayOne, arrayTwo, arrayThree }.SelectMany(x => x);

Upvotes: 2

spender
spender

Reputation: 120518

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);

Upvotes: 9

Yeldar Kurmangaliyev
Yeldar Kurmangaliyev

Reputation: 34244

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.

Upvotes: 14

Optional Option
Optional Option

Reputation: 1571

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.

Upvotes: 0

BurnsBA
BurnsBA

Reputation: 4939

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}");
}

Upvotes: 2

Related Questions