Get sub array from a 3D array - c#

If I have an array:
int[,,] mainArray = new int[10,10,3];
How can I get a sub array:
int[] sub = mainArray[0,1]; // Unfortunately this doesn't work
Where sub would contain the 3 elements
sub[0] = mainArray[0,1,0];
sub[1] = mainArray[0,1,1];
sub[2] = mainArray[0,1,2];
It would be easy to write a method to do this but is there a built in way to do it?

I think you can use an extension method like this:
public static class MyExtensions
{
public static int[] GetValues(this Array source, int x, int y)
{
var length = source.GetUpperBound(2);
var values = new int[length+1];
for (int i = 0; i < length+1; i++)
{
values[i] = (int)source.GetValue(x, y, i);
}
return values;
}
}
Usage:
int[,,] mainArray = new int[10,10,3];
int[] sub = mainArray.GetValues(0, 1);

You could use nested arrays instead.
// Initialization
int[][][] mainArray = new int[10][][];
for (int i = 0; i < mainArray.Length; i++)
{
mainArray[i] = new int[10][];
for (int j = 0; j < mainArray[i].Length; j++)
{
mainArray[i][j] = new int[3];
}
}
// Usage
int[] sub = mainArray[0][1];
Yes, the initialization is a bit more complex, but other than that it's all the same. And nested arrays even have better performance (but you shouldn't care about array performance unless your profiler told you so).
Here is a helper class I wrote to help with the initialization of nested arrays.
public static class NestedArray
{
public static Array Create<T>(params int[] lengths)
{
Type arrayType = typeof(T);
for (int i = 0; i < lengths.Length - 1; i++)
arrayType = arrayType.MakeArrayType();
return CreateArray(arrayType, lengths[0], lengths.Skip(1).ToArray());
}
private static Array CreateArray(Type elementType, int length, params int[] subLengths)
{
Array array = Array.CreateInstance(elementType, length);
if (subLengths.Length > 0)
{
for (int i = 0; i < length; i++)
{
Array nestedArray = CreateArray(elementType.GetElementType(), subLengths[0], subLengths.Skip(1).ToArray());
array.SetValue(nestedArray, i);
}
}
return array;
}
}
Usage:
int[][][] mainArray = (int[][][])NestedArray.Create<int>(10, 10, 3);
Full commented source code can be found in this gist.

You can use Buffer.BlockCopy and some math, if you always want the the last dimension:
Buffer.BlockCopy(mainArray, (D2*i+j)*D3*sizeof(TYPE), sub, 0, D3*sizeof(TYPE));
will put mainArray[i,j,] in sub, where D1, D2, and D3 are your dimensions and TYPE is the type of the array elements.

Related

Create a dynamically dimensioned Array or List

I want to create an Array or a List with N-Dimensions.
Is there a way to do this without having a Method for each possible dimension:
private ____ createArray(int dimensions, int[] lengths)
{
// declare array with dimensions from variable dimensions
// set length of first dimension to lengths[0]
// set length of second dimension to lengths[1]
// [...]
// return array
}
And not like this
private int[][][] create3DArray(int[] lengths)
{
int[][][] array = new int[lengths[0]][][];
int[] newLengths = new int[lengths.Count - 1];
for(int i = 0; i < lengths.Count - 1; i++)
{
newLengths[i] = lengths[i + 1];
}
for(int i = 0; i < lengths[0]; i++)
{
array[i] = create2DArray(newLengths);
}
return array;
}
private int[][] create2DArray(int[] lengths)
{
int[][] array = new int[lengths[0]][];
for(int i = 0; i < lengths.Count; i++)
{
array[i] = new int[lengths[1]];
}
return array;
}
If I have to do it like this, I need to have a method for every possible (let's ignore the fact that it may not make sense to have an array with N-Dimensions) amount of dimensions.
you can create a list of lists:
var myList = new List<List<int>>();
for(int i = 0; i < 10; ++i) {
var localList = new List<int>();
myList.Add(localList);
}
You could create like this using Enumerable.Repeat as many levels as you want:
int x = 5, y = 6, z = 7;
List<List<List<int>>> list3D = Enumerable.Repeat<List<List<int>>>(
new List<List<int>>(
Enumerable.Repeat<List<int>>(
new List<int>(
Enumerable.Repeat<int>(0, z)
), y)
), x
).ToList();
}
In the example above you create 3D lists with initial value of 0 and initial size of 5x6x7
It is possible.
Make an int array of dimensions. From there, you can create a conditional var declaration. The only trick is that you need to make explicit the conversion to (Array)

How to copy C# 3D jagged array

I need to (initially) copy a C# 3D jagged array, foos, to another 3D array (and eventually add x, y, z dimensions). I thought I could use the same syntax/logic to copy foos as was used to build foos as I've done below (where row = 2, col = 3, z = 4):
private static void copyFooArray(Foo[][][] foos, ref Foo[][][] newArray)
{
for (int row = 0; row < foos.Length; row++)
{
newArray[row] = new Foo[foos[row].Length][];
for (int col = 0; col < foos[row].Length; col++)
{
newArray[row][col] = new Foo[foos[row][col].Length];
for (int z= 0; z< foos[row][col].Length; z++)
{
newArray[row][col][z] = new Foo();
newArray[row][col][z].member = foos[row][col][z].member;
}
}
}
Console.Read();
}
but I'm getting Index was outside the bounds of the array. on this line:
newArray[row] = new Foo[foos[row].Length][];
Why?
Foo Class:
public class Foo
{
public string member;
}
Thanks.
It doesn't look like your referenced array is being initialized properly. In order to set the value, your newArray must be initialized as the same size of your original.
For this to work you'd need to pass in something like this:
Foo[][][] firstFoo = new Foo[10][][];
Foo[][][] fooToCopy = new Foo[firstFoo.Length][][];
copyFooArray(firstFoo, ref fooToCopy);
Also, the ref keyword is unnecessary since arrays are passed by reference in c# anyways.
In addition to the fix presented in the accepted answer, here's a faster way to do that:
public static int[][][] Copy(int[][][] source)
{
int[][][] dest = new int[source.Length][][];
for (int x = 0; x < source.Length; x++)
{
int[][] s = new int[source[x].Length][];
for (int y = 0; y < source[x].Length; y++)
{
int[] n = new int[source[x][y].Length];
int length = source[x][y].Length * sizeof(int);
Buffer.BlockCopy(source[x][y], 0, n, 0, length);
s[y] = n;
}
dest[x] = s;
}
return dest;
}

Combining two single dimensional arrays in a 2D array in c#

I am having two 1D arrays. I want to convert these 2 arrays as single 2D array.
My code is:
public Static void Main()
{
int[] arrayRow;
int[] arrayCol;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
int[,] myArray = new int[row,column];
myArray[i,j] = arrayRow[i]; // not possible -- your suggestions
}
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Console.Write(myArray[i,j]);
}
}
}
I need to save arrayRow[] and arrayCol[] in myArray[,].
For example,
if we have arrayRow[]={1,2,3} and arrayCol[]={4,5,6} then myArray[,]={(1,4),(2,5),(3,6)}
Note: arrayRow and arrayCol may have different lengths. In such cases the element that have no pair should be stored in the new single dimensional array result[].
Your arrayRow[] and arrayCol[] will be just two lines of a two-dimensional array (if you didn't mean jagged one).
So the code to unite two arrays into one is just:
public static T[,] Union<T>(T[] first, T[] second) //where T : struct
{
T[,] result = new T[2, Math.Max(first.Length, second.Length)];
int firstArrayLength = first.Length * Marshal.SizeOf(typeof(T));
Buffer.BlockCopy(first, 0, result, 0, firstArrayLength);
Buffer.BlockCopy(second, 0, result, firstArrayLength, second.Length * Marshal.SizeOf(typeof(T)));
return result;
}
As it have been mentinoned, BlockCopy is cooler than for cycle.
If you do mean that you need a jagged array (like int[][]), that the solutiona will be way more simplier:
public static T[][] UnionJagged<T>(T[] first, T[] second)
{
return new T[2][] { first, second };
}
Which transforms into even simplier if we add multiple-array-as-parameters functionality:
public static T[][] UnionJagged<T>(params T[][] arrays)
{
return arrays;
}
static void Main()
{
int[] a = new int[] { 10, 2, 3 };
int[] b = new int[] { -1, 2, -3 };
int[] c = new int[] { 1, -2, 3 };
int[][] jaggedThing = UnionJagged(a, b, c);
}
Didn't tryed this, and I'm just guessing what you want to acomplish, but here it is:
int[] arrayRow;
int[] arrayCol;
int[,] myArray = new int[Math.Max(arrayRow.Length, arrayCol.Length), 2];
for (int i = 0; i < arrayRow.Length; i++)
myArray[i, 0] = arrayRow[i];
for (int i = 0; i < arrayCol.Length; i++)
myArray[i, 1] = arrayCol[i];
More performant / another way:
public static void ConvertFlatArrayToMatrix(int[] array, int[,] matrix, int dimension) {
for(int i = 0; i < array.Length; i++) {
int r = Mathf.FloorToInt(i / dimension);
int c = i % dimension;
matrix[c,r] = array[i];
}
}
This will just push the result into a 2d array you pass in.
Keep in mind, I'm not checking length or protecting against anything here, this is just the concept and the bare minimum to get the job done.

Convert a C# jagged array to an array and back again

I currently have a jagged array Class[][][] which I want to serialise as a normal Class[] array, then convert back into a Class[][][] array after deserialization. Is it at all possible to convert between the two both ways? The dimensions are of constant sizes.
This is how you can flatten to a 1-dimensional structure:
var jagged = new object[][][];
var flattened = jagged.SelectMany(inner => inner.SelectMany(innerInner => innerInner)).ToArray();
As for going back to multidimensional - this will depend entirely on what it is your trying to achieve/what the data represents
If you don't mind serializing a flattened array and an array of ints, you can use the following:
public static int[] JaggedSizes<T>(this T[][][] topArray)
{
List<int> rtn = new List<int>();
rtn.Add(topArray.Length);
for (int i = 0; i < topArray.Length; i++)
{
var midArray = topArray[i];
rtn.Add(midArray.Length);
for (int j = 0; j < midArray.Length; j++)
{
var botArray = midArray[j];
rtn.Add(botArray.Length);
}
}
return rtn.ToArray();
}
// Thanks #Dave Bish
public static T[] ToFlat<T>(this T[][][] jagged)
{
return jagged.SelectMany(inner =>
inner.SelectMany(innerInner => innerInner)).ToArray();
}
public static T[][][] FromFlatWithSizes<T>(this T[] flat, int[] sizes)
{
int inPtr = 0;
int sPtr = 0;
int topSize = sizes[sPtr++];
T[][][] rtn = new T[topSize][][];
for (int i = 0; i < topSize; i++)
{
int midSize = sizes[sPtr++];
T[][] mid = new T[midSize][];
rtn[i] = mid;
for (int j = 0; j < midSize; j++)
{
int botSize = sizes[sPtr++];
T[] bot = new T[botSize];
mid[j] = bot;
for (int k = 0; k < botSize; k++)
{
bot[k] = flat[inPtr++];
}
}
}
return rtn;
}
I don't think so Rory.
You may have been able to do this if it is a Class[,,] multidimensional array, but the fact that each array could be of different length is going to always be a stumbling block.
Assuming you serialize if as a Class[] + another class to give you the original dimensions, you'll be golden.

c# assign 1 dimensional array to 2 dimensional array syntax

I want to do something like:
object[] rowOfObjects = GetRow();//filled somewhere else
object[,] tableOfObjects = new object[10,10];
tableOfObjects[0] = rowOfObjects;
is this somehow possible and what is the syntax?
or I need to do this:
for (int i = 0; i < rowOfObjects.Length; i++)
{
tableOfObjects[0,i] = rowOfObjects[i];
}
and fill up the 2 dimensional arrays row using a loop?
Thanks
No, if you are using a two dimensional array it's not possible. You have to copy each item.
If you use a jagged array, it works just fine:
// create array of arrays
object[][] tableOfObject = new object[10][];
// create arrays to put in the array of arrays
for (int i = 0; i < 10; i++) tableOfObject[i] = new object[10];
// get row as array
object[] rowOfObject = GetRow();
// put array in array of arrays
tableOfObjects[0] = rowOfObjects;
If you are getting all the data as rows, you of course don't need the loop that puts arrays in the array of arrays, as you would just replace them anyway.
If your array is an array of value types, it is possible.
int[,] twoD = new int[2, 2] {
{0,1},
{2,3}
};
int[] oneD = new int[2]
{ 4, 5 };
int destRow = 1;
Buffer.BlockCopy(
oneD, // src
0, // srcOffset
twoD, // dst
destRow * twoD.GetLength(1) * sizeof(int), // dstOffset
oneD.Length * sizeof(int)); // count
// twoD now equals
// {0,1},
// {4,5}
It is not possible with an array of objects.
Note: Since .net3.5 this will only work with an array of primitives.
if I have gigabyte size arrays, I would do it in C++/CLI playing with pointers and doing just memcpy instead of having gazillion slow boundary-checked array indexing operations.
I find it easiest to just do a loop.
public static double[,] arraycopy(double[]
thearray, int n, int nrow, int ncol)
{
double[] sourcearray;
double[,] newarray;
int i = 0;
int j = 0;
sourcearray = new double[n];
sourcearray = thearray;
newarray = new double[nrow, ncol];
for(i=0; i<nrow; i++)
{
for(j=0; j<ncol; j++)
newarray[i,j] = sourcearray[nrow*i + j];
}
return newarray;
}
So, Something like:
public static object[] GetRow()
{
object[,] test = new object[10,10];
int a = 0;
object[] row = new object[10];
for(a = 0; a <= 10; a++)
{
row[a] = test[0, a];
}
return row;
}

Categories