C
C#9mo ago
BenMcLean

❔ Combine two arrays by alternating items?

Let's imagine I have two arrays, A and B, which each have four items. I want to make a new array C which is made up of the contents of A and B. so
T[] c = new T[a.Length + b.Length];//8
c[0]=a[0];
c[1]=b[0];
c[2]=a[1];
c[3]=b[1];
c[4]=a[2];
c[5]=b[2];
c[6]=a[3];
c[7]=b[3];
T[] c = new T[a.Length + b.Length];//8
c[0]=a[0];
c[1]=b[0];
c[2]=a[1];
c[3]=b[1];
c[4]=a[2];
c[5]=b[2];
c[6]=a[3];
c[7]=b[3];
Except can I do this with LINQ? And for any arbitrary size?
22 Replies
reflectronic
reflectronic9mo ago
it is possibile to do with LINQ but a for loop will be the clearest and easiest way, by far
BenMcLean
BenMcLean9mo ago
In my use case, the two source arrays are of equal size ... I'm not sure what I'd want this method to do in the case of arrays of different sizes How about this maybe?
/// <summary>
/// Combines arrays by alternating one item from each
/// </summary>
/// <param name="list">All arrays after list[0] must be sized equal to or greater than list[0]</param>
/// <returns>Array of size list[0].Length * list.Length</returns>
public static T[] CombineArrays<T>(params T[][] list)
{
T[] result = new T[list[0].Length * list.Length];
for (int x = 0, z = 0; x < list[0].Length; x++, z += list.Length)
for (int y = 0; y < list.Length; y++)
result[z + y] = list[x][y];
return result;
}
/// <summary>
/// Combines arrays by alternating one item from each
/// </summary>
/// <param name="list">All arrays after list[0] must be sized equal to or greater than list[0]</param>
/// <returns>Array of size list[0].Length * list.Length</returns>
public static T[] CombineArrays<T>(params T[][] list)
{
T[] result = new T[list[0].Length * list.Length];
for (int x = 0, z = 0; x < list[0].Length; x++, z += list.Length)
for (int y = 0; y < list.Length; y++)
result[z + y] = list[x][y];
return result;
}
That one should keep going until it runs out of items from the first array, and it assumes that all the arrays after the first array will have at least as many items as the first array.
Moods
Moods9mo ago
Is that how params works
BenMcLean
BenMcLean9mo ago
I think so yeah
MKP
MKP9mo ago
params is basically an array of a type
Moods
Moods9mo ago
I was referring to params having to be a single dimensional array But i could be wrong
BenMcLean
BenMcLean9mo ago
I know this works because I have used it before:
public static T[] ConcatArrays<T>(params T[][] list)
{
T[] result = new T[list.Sum(a => a.Length)];
for (int i = 0, offset = 0; i < list.Length; i++)
{
list[i].CopyTo(result, offset);
offset += list[i].Length;
}
return result;
}
public static T[] ConcatArrays<T>(params T[][] list)
{
T[] result = new T[list.Sum(a => a.Length)];
for (int i = 0, offset = 0; i < list.Length; i++)
{
list[i].CopyTo(result, offset);
offset += list[i].Length;
}
return result;
}
MKP
MKP9mo ago
thats what I said yea
BenMcLean
BenMcLean9mo ago
No, params can be a multi dimensional array. You can call the method with a multi dimensional array of that same size or you can call it with multiple parameters of one dimension smaller arrays. However, from looking at this, I strongly suspect I constructed my for loops incorrectly
Moods
Moods9mo ago
Okay so, you have a varying number of arrays of different length
BenMcLean
BenMcLean9mo ago
Oh wait, no I didn't, I used z
Moods
Moods9mo ago
And you want to combine them into one array with alternating values inserted
BenMcLean
BenMcLean9mo ago
Yeah but I updated to specify that all arrays after the first one must be equal to or greater than the first one's in length. That makes my code simpler. right
Moods
Moods9mo ago
How so? You can still have varying array lengths, you just have a minimum size now
BenMcLean
BenMcLean9mo ago
right
Moods
Moods9mo ago
Basically you wanna loop through the list of arrays, adding the first unused value to the resulting array Might be easier to use a List to hold the values then you could ToArray it at the end (that’s a function right?)
BenMcLean
BenMcLean9mo ago
I think I should change that one line to result[z + y] = list[y][x]; How would that help
Moods
Moods9mo ago
Cus you wouldn’t really have to worry about what index the result would be Just call result.Add As long as you get the order right The thing is going from your example you could have, for example 5 arrays, of respective lengths of 4, 4, 6, 4, 7. You would have to do some bounds checking
BenMcLean
BenMcLean9mo ago
I managed to confirm it works with a unit test.
public static T[] CombineArrays<T>(params T[][] list)
{
T[] result = new T[list[0].Length * list.Length];
for (int x = 0, z = 0; x < list[0].Length; x++, z += list.Length)
for (int y = 0; y < list.Length; y++)
result[z + y] = list[y][x];
return result;
}
[Fact]
public void CombineArraysTest()
{
char[] a = new char[] { 'a', 'c', 'e', 'g' };
char[] b = new char[] { 'b', 'd', 'f', 'h' };
char[] combined = CombineArrays(a, b);
Assert.Equal(
expected: 8,
actual: combined.Length);
Assert.Equal(
expected: 'a',
actual: combined[0]);
Assert.Equal(
expected: 'b',
actual: combined[1]);
Assert.Equal(
expected: 'c',
actual: combined[2]);
Assert.Equal(
expected: 'd',
actual: combined[3]);
Assert.Equal(
expected: 'e',
actual: combined[4]);
Assert.Equal(
expected: 'f',
actual: combined[5]);
Assert.Equal(
expected: 'g',
actual: combined[6]);
Assert.Equal(
expected: 'h',
actual: combined[7]);
}
public static T[] CombineArrays<T>(params T[][] list)
{
T[] result = new T[list[0].Length * list.Length];
for (int x = 0, z = 0; x < list[0].Length; x++, z += list.Length)
for (int y = 0; y < list.Length; y++)
result[z + y] = list[y][x];
return result;
}
[Fact]
public void CombineArraysTest()
{
char[] a = new char[] { 'a', 'c', 'e', 'g' };
char[] b = new char[] { 'b', 'd', 'f', 'h' };
char[] combined = CombineArrays(a, b);
Assert.Equal(
expected: 8,
actual: combined.Length);
Assert.Equal(
expected: 'a',
actual: combined[0]);
Assert.Equal(
expected: 'b',
actual: combined[1]);
Assert.Equal(
expected: 'c',
actual: combined[2]);
Assert.Equal(
expected: 'd',
actual: combined[3]);
Assert.Equal(
expected: 'e',
actual: combined[4]);
Assert.Equal(
expected: 'f',
actual: combined[5]);
Assert.Equal(
expected: 'g',
actual: combined[6]);
Assert.Equal(
expected: 'h',
actual: combined[7]);
}
Well no, I'd just have to document the requirement about array sizes, which I did with a comment. This is actually being used in a situation where all the arrays will always be of equal size
Moods
Moods9mo ago
Oh that makes it easier then Just loop through the list of arrays adding the value of the value at the first unused index Ig you could use a nested loop I don’t know how you’d do it with LINQ though
BenMcLean
BenMcLean9mo ago
That's what I did in that template method I posted
Accord
Accord9mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.