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)
Related
I have a 2D array of type string which I want to modify and resize inside some loop. My main goal is to use minimum memory by creating a 2d array which will be modified every iteration of loop and the add a char to an appropriate cell in this array. Here is my code:
static void Main(string[] args)
{
int maxBound = 100;//length of freq array
Random rnd1 = new Random();
int numLoops = rnd1.Next(1000, 1200);//number of total elements in freq array
int[] freq = new int[maxBound];//freq array
string[,] _2dim = new string[maxBound, numLoops];//rows,columns
Random rnd2 = new Random();
for (int i = 0; i < numLoops; i++)
{
int s = rnd2.Next(maxBound);
freq[s]++;
//Here I try to add `*` to the _2dim array while resizing it to the appropriate size
}
}
What is the main approach for the solution ? Thanks
Instead of a 2D array you might want to use a jagged one. Briefly, a 2D array is always an N x M matrix, which you cannot resize, whereas a jagged array is an array of arrays, where you can separately initialize every inner element by a different size (see the differences in details here)
int maxBound = 100;
Random rnd = new Random();
int numLoops = rnd.Next(1000, 1200);
string[][] jagged = new string[numLoops][];
for (int i = 0; i < numLoops; i++)
{
int currLen = rnd.Next(maxBound);
jagged[i] = new string[currLen];
for (int j = 0; j < currLen; j++)
jagged[i][j] = "*"; // do some initialization
}
You should use a list of type string nested in a List. Then you can modify this lists. For iterating through this you should use two for loops.
List<List<string>> l = new List<List<string>> { new List<string> { "a", "b" }, new List<string> { "1", "2" } };
Iteration example:
for(int i = 0; i < l.Count; i++)
{
for(int j = 0; j < l[i].Count; j++)
{
Console.WriteLine(l[i][j]);
}
}
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;
}
Consider the following array:
private int[][] Blocks;
How can I specify each of this array's sizes separately?
Something like so was my first idea: (throws an error though)
Blocks = new int[5][];
Blocks = new int[][7];
Errors come as following:
Wrong number of indices inside []; expected 1
Array creation must have array size or array initializer
Invalid rank specifier ',' or ']'
There are two ways of declaring arrays in two dimensions.
True 2-dimensional arrays
Jagged arrays
A two dimensional array is one single array with two dimensions, i.e. one matrix. It has a rectangular shape:
int[,] twoDimensionalArray = new int[5, 7];
You can loop through all elements of a two dimensional array like this:
for (int i = 0; i < twoDimensionalArray.GetLength(0); i++) {
for (int j = 0; j < twoDimensionalArray.GetLength(1); j++) {
int element = twoDimensionalArray[i, j];
// TODO: Do something with element.
}
}
If the array is of constant size, declare constants for the size:
const int ArrWidth = 5, ArrHeight = 7;
int[,] twoDimensionalArray = new int[ArrWidth, ArrHeight];
for (int i = 0; i < ArrWidth; i++) {
for (int j = 0; j < ArrHeight; j++) {
int element = twoDimensionalArray[i, j];
// TODO: Do something with element.
}
}
You can also enumerate all elements of a multi-dimensional array as a flattened enumeration with foreach:
foreach (int element in twoDimensionalArray) {
// TODO: Do something with element.
}
A jagged array is an array of arrays. You must create the array in two steps:
// First create the base (or outer) array
int[][] jaggedArray = new int[5][];
// Then create the nested (or innner) arrays
jaggedArray[0] = new int[7];
jaggedArray[1] = new int[2];
jaggedArray[2] = new int[11];
jaggedArray[3] = new int[0];
jaggedArray[4] = new int[4];
Because the nested arrays can have different sizes, this type of array is called "jagged".
You can loop through all elements of a jagged array like this:
for (int i = 0; i < jaggedArray.Length; i++) {
int[] inner = jaggedArray[i];
if (inner != null) {
for (int j = 0; j < inner.Length; j++) {
int element = inner[j];
// TODO: Do something with element.
}
}
}
You can leave out the null-test, if you know that you have initialized all inner arrays.
This
int[][] blocks = ...
is an array of arrays.
what you want probably, is a 2-dimensional array, which is declared like this:
int[,] blocks = new int[5,7];
If you really want an array of arrays, you can only declare the first 'dimension' like this:
int[][] block = new int[5][];
This creates an array of 5 (nulls).
Now you have to create each of those 'subarrays' like this:
block[0] = new int[3];
block[1] = new int [20];
The dieffernece here is, that each "subarray" can have a totally different size, compared to the 2-dimensional array.
what do you declare is an array of arrays so you have two cases.
Blocks = new int[5][];
the first is the size of the content of the array have same dimension
for (int i = 0; i < Blocks.Length; i++)
Blocks[i] = new int[8];
the second is the size of the content of the array have different dimension:
Blocks[0] = new int[6];
Blocks[1] = new int[4];
Blocks[2] = new int[10];
Blocks[3] = new int[7];
Blocks[4] = new int[3];
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.
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;
}