C# - Access a one slice of a multi-dimensional array - c#

Suppose a have a MxNx3 matrix
byte [,,] myMatrix= new byte[sizeRow, sizeCol, 3];
How do I access a single band of it (for read and write purposes)? Something like:
singleBand = myMatrix[:allRows: , :allCols: , :desiredBand:];
On the left is what I have, of the right is what I want to access (for example).

int M=10;
int N=20;
var test = new byte[3][,] { new byte[N,M],new byte[N,M],new byte[N,M]};
var band1 = test[1]; //its green
band1[2, 2] = 99;

If you can't change the type of myMatrix, then you can use the following code:
byte [,,] myMatrix= new byte[sizeRow, sizeCol, 3];
var singleBand = new byte[sizeRow, sizeCol];
var band = 1;
for (var i = 0; i < sizeRow; i++) {
for (var j = 0; j < sizeCol; j++) {
singleBand[i, j] = myMatrix[i, j, band];
}
}
But if you can change it, then probably Zeromus' solution is better, since you can more easily manipulate with what you call the band.

You simply need to loop through your required array elements and extract the "band" that you need.
// Create a three-dimensional array.
int[, ,] threeDimensional = new int[3, 3, 3];
// Set the first "Band" to 9
threeDimensional[0,0,1] = 9;
threeDimensional[1,0,1] = 9;
threeDimensional[2,0,1] = 9;
threeDimensional[0,1,1] = 9;
threeDimensional[1,1,1] = 9;
threeDimensional[2,1,1] = 9;
threeDimensional[0,2,1] = 9;
threeDimensional[1,2,1] = 9;
threeDimensional[2,2,1] = 9;
// Loop over each dimension's length.
for (int i = 0; i < threeDimensional.GetLength(2); i++)
{
for (int y = 0; y < threeDimensional.GetLength(1); y++)
{
for (int x = 0; x < threeDimensional.GetLength(0); x++)
{
Console.Write(threeDimensional[x, y, i]);
}
Console.WriteLine();
}
Console.WriteLine();
}
Your only option is to access each "cell" in the band one at a time and extract it to some other location. In my case i just put them out to the display.

Related

Fill 2d array with unique random numbers from 0 to 15 C#

I can't fill it with numbers to 0 - 15 then shuffle the array, so that's not the solution
I used this code in C but now in c# it doesn't work, for some reason this code let some numbers pass the do while.
Random r = new Random();
bool unique;
int rand_num;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
do
{
unique = true;
rand_num = r.Next(16);
for (int k = 0; k < 4; k++)
{
for (int l = 0; l < 4; l++)
{
if (numbers[k, j] == rand_num)
{
unique = false;
}
}
}
} while (!unique);
numbers[i, j] = rand_num;
}
}
}
If the list of possible numbers is small, as in this case, just create the full list and randomise it first, then take the items in the order they appear. In your case, you can put the randomised numbers into a queue, then dequeue as required.
var r = new Random();
var numberQueue = new Queue<int>(Enumerable.Range(0, 16).OrderBy(n => r.NextDouble()));
var numbers = new int[4, 4];
for (var i = 0; i <= numbers.GetUpperBound(0); i++)
{
for (var j = 0; j <= numbers.GetUpperBound(1); j++)
{
numbers[i, j] = numberQueue.Dequeue();
}
}
I suggest you to use the Fisher-Yates algorithm to generate your non-repeatable sequence of random numbers.
It would be very straight-forward to implement a code to fill in a 2d array with those numbers, then.
List<int> seq = Enumerable.Range(0,16).ToList();
int[,] numbers = new int[4,4];
Random r = new();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int n = r.Next(0, seq.Count);
numbers[i,j] = seq[n];
seq.RemoveAt(n);
}
}
The approach you have taken may end up in continuous looping and take lot of time to complete.
Also checking for value in 2D using nested for loop is not efficient.
You can use HashSet to keep track of unique value. Searching in HashSet is fast.
following is the code approach I suggest.
var hashSet = new HashSet<int>();
var r = new Random();
var arr = new int[4, 4];
for(var i = 0;i<4;i++)
{
for(var j = 0;j<4;j++)
{
// Generate random value between 0 and 16.
var v = r.Next(0, 16);
// Check if the hashSet has the newly generated random value.
while(hashSet.Contains(v))
{
// generate new random value if the hashSet has the earlier generated value.
v = r.Next(0, 16);
}
//Add value to the hashSet.
hashSet.Add(v);
// add value to the 2D array.
arr[i, j] = v;
}
}
I hope this will help solving your issue.
The problem with your current approach is that as you get closer to the end of the array, you have to work harder and harder to get the next random value.
Imagine you roll a die, and each time you want to get a unique value. The first time you roll, any result will be unique. The next time, you have a 1/6 chance of getting a number that has already been obtained. And then a 2/6 chance, etc. and in the end most of your rolls will be non-unique.
In your example, you have 16 places that you want to fill with numbers 0 to 15. This is not a case of randomly generating numbers, but randomly placing them. How do we do this with a deck of cards? We shufle them!
My proposal is that you fill the array with unique sequential values and then shuffle them:
Random random = new Random();
int dim1 = array.GetLength(0);
int dim2 = array.GetLength(1);
int length = dim1 * dim2;
for (int i = 0; i < length; ++i)
{
int x = i / dim1;
int y = i % dim1;
array[x, y] = i; // set the initial values for each cell
}
// shuffle the values randomly
for (int i = 0; i < length; ++i)
{
int x1 = i / dim1;
int y1 = i % dim1;
int randPos = random.Next(i, length);
int x2 = randPos / dim1;
int y2 = randPos % dim1;
int tmp = array[x1, y1];
array[x1, y1] = array[x2, y2];
array[x2, y2] = tmp;
}
The shuffle in this code is based on the shuffle found here
int[,] numbers = new int[4, 4];
Random r = new Random();
bool unique;
int rand_num;
List<int> listRandom = new List<int> { };
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 4; j++ )
{
do
{
unique = false;
if (!listRandom.Contains( rand_num = r.Next( 0, 16 )))
{
listRandom.Add( rand_num );
numbers[i, j] = rand_num;
unique = true;
}
} while ( !unique );
}
}

Create an Array of arrays of arrays of different shapes

I am trying to create an array of 6 arrays each containing 4 arrays, each of those 4 arrays with different shape.
Like in the form below:
[[array([[1,2,3,4,6,5],
[5,6,6,7,7,5],
[6,6,5,5,6,5],
[4,6,6,7,7,5],
[5,6,6,7,7,5],
[6,6,5,5,6,5],
[6,6,5,5,6,5],]),
array([[9,9,9],
[9,9,9],
[6,6,6],
[3,3,6],
[6,6,6]]),
array([[6],
[7],
[7],
[7],
[7]]),
array([[7,8,8,8,8]])],
[[array([[1,2,3,4,6,5],
[5,6,6,7,7,5],
[6,6,5,5,6,5],
[4,6,6,7,7,5],
[5,6,6,7,7,5],
[6,6,5,5,6,5],
[6,6,5,5,6,5],]),
array([[9,9,9],
[9,9,9],
[6,6,6],
[3,3,6],
[6,6,6]]),
array([[6],
[7],
[7],
[7],
[7]]),
array([[7,8,8,8,8]])]]
..........
I have this code but I am doing something wrong, I do not get the desired shape.
Can somebody please help me with this?
int populationSize = 6;
double[][][][] population = new double[populationSize][][][];
int value = 3;
for (int i = 0; i < populationSize; i++)
{
population[i] = new double[4][][];
for (int j = 0; j < 4; j++)
{
const int rows = 7, cols = 6;
population[i][j] = new double[rows][];
for (int k = 0; k < rows; k++)
{
population[i][j][k] = new double[cols];
for (int m = 0; m < cols; m++)
{
population[i][j][k][m] = value;
}
}
}
}
const int rows = 7, cols = 6;
population[j][j] = new double[5][];
for (int k = 0; k < rows; k++)
you are using the same indexes for population[j][j], that is probably incorrect.
You are also specifying 7 rows, but create a matrix of size 5. That is probably incorrect.
As Scopperloit points out, you probably want:
const int rows = 7, cols = 6;
population[i][j] = new double[rows][];
for (int k = 0; k < rows; k++)
Overall when debugging problems. Run the code in a debugger and inspect the values against your expectations. Index out of range exceptions are usually very easy to debug:
What is the index?
What is the length of the array?
Is the index or array length incorrect?
I managed to solve my problem.
THis function creates an array of arrays of arrays of different shapes according to another array, and fills it with random normal standard distribution values :
int[,] netshape = new int[,] { { 3, 4}, { 4, 5}, { 4, 1 }, { 1, 4} }; // The shape of the network
public double[][][][] CreateNetwork(int[,] netshape,int populationSize )
{
normal = new MathNet.Numerics.Distributions.Normal(0, 1);// Generate random normal standard distribution
int rows, cols ;
double[][][][] population = new double[populationSize][][][];
for (int i = 0; i < populationSize; i++)
{
population[i] = new double[4][][];
for (int j = 0; j < 4; j++)
{
rows = netshape[j, 0];
cols = netshape[j, 1];
population[i][j] = new double[rows][];
for (int k = 0; k < rows; k++)
{
population[i][j][k] = new double[cols];
for (int m = 0; m < cols; m++)
{
population[i][j][k][m] = normal.Sample(); ;
}
}
}
}
return population;
}

Limit the array size 2D (C# UNITY)

Hello guys is it possible to limit the array size just like this example
Now i want only to show 6 of them.
What i have done so far is this
CustomClass
const int MAX = 104; // = 8 decks * 52 cards / 4cardsoneround
const int Y = 6;
int[,] arrayRoad = new int[Y, X];
public int[,] GetRoad(int x) {
arrayRoad = new int[x, 6];
return arrayRoad;
}
Now I'm displaying it on my MainClass like this
ScoreBoard bsb = new ScoreBoard();
private void Road()
{
bsb.makeRoad(history); // Road
int[,] arrayRoad = bsb.GetRoad(6); //<--- sample value 6
string s = "";
for (int y = 0; y < arrayRoad.GetLength(0); y++)
{
//just 27 for now
for (int x = 0; x < 28; x++)
{
s += string.Format("{0:D2}",arrayRoad[y, x]);
s += ".";
}
s += "\n";
}
Debug.Log(s);
}
The problem with this code is that it's giving me an Array out of index
Is this possible??
Updated
public int[,] GetRoad(int x = MAX,int y = Y) {
arrayRoad = new int[y, x];
return arrayRoad;
}
Where in my Max = 104 and Y = 6
int[,] arrayRoad = bsb.GetRoad(12,6); //12 rows and 6 in height
string s = "";
for (int y = 0; y < arrayRoad.GetLength(0); y++)
{
for (int x = 0; x < arrayRoad.GetLength(1); x++)
{
s += string.Format("{0:D2}",arrayRoad[y, x]);
s += ".";
}
s += "\n";
}
Debug.Log(s);
}
I have all this value earlier before i perform the update code
Now when i perform the updated code here's what I got
The expected result must be this
Inside of that black marker those twelve columns only must be shown because i declared on my
int[,] arrayRoad = bsb.GetRoad(12,6);
Note this:
public int[,] GetBigEyeRoad(int x) {
arrayRoad = new int[x, 6]; // <-------------
return arrayBigEyeRoad;
There you are fixing the length of the second dimension of the array to 6.
for (int x = 0; x < 28; x++)
{
s += string.Format("{0:D2}",arrayBigEyeRoad[y, x]); // <------------
There, you are trying to access indices up to 28 on the second dimension of the array. The Out of Range error comes from that.
What I did here was copy my old array to the new one just like this code below
int[,] arrayBigRoadResult = new int[6, x];
//copy manually the element references inside array
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < x; j++)
{
arrayBigRoadResult[i, j] = arrayBigRoad[i, j];
}
}
return arrayBigRoadResult;
then by calling it just like this
int[,] arrayRoad = bsb.GetRoad(12);
It would only display 12 columns and 6 rows :)

Variable parameter in the definition of array

I have the following code, which creates a 2D array in a nested loop, What I want to do is to create this 2D array each iteration but with name concatenated to "j" value . For example,
In first iteration the result will be : double[,] visualmatrix1.
I tried to put +j but it fails.
ExtractDescriptorsForm ex = new ExtractDescriptorsForm(65,10);
int a = ex.m_maxExtract;
for (int i = 0; i < m_descriptor.visualword.Length; i++)
{
for (int j = 0; j < a; j++)
{
double[,] visualmatrix = new double[m_descriptor.visualword.Length, 2];
visualmatrix[i, 0] = m_descriptor.visualword[i].identifier;
visualmatrix[i, 1] = (m_descriptor.visualword[i].tf) * (m_descriptor.visualword[i].idf);
}
}
Since your code lost the new-created array inside the loops, you should use a list to store the 2D arrays.
List<double[,]> arrays = new List<double[,]>();
ExtractDescriptorsForm ex = new ExtractDescriptorsForm(65,10);
int a = ex.m_maxExtract;
for (int i = 0; i < m_descriptor.visualword.Length; i++)
{
for (int j = 0; j < a; j++)
{
double[,] visualmatrix = new double[m_descriptor.visualword.Length, 2];
visualmatrix[i, 0] = m_descriptor.visualword[i].identifier;
visualmatrix[i, 1] = (m_descriptor.visualword[i].tf) * (m_descriptor.visualword[i].idf);
arrays.Add(visualmatrix);
}
}
Then access it by
arrays[n]

load string array dynamically at runtime

I currently want a 2D array (4,4) to look like this:
outArr = new string[4, 4]
{
{"0","0","0","0" },
{"0","0","0","0" },
{"0","0","0","0" },
{"0","0","0","0" }
};
However, I'm unsure of how to do with in code where the array sizes could be dynamic at runtime (i.e. 3,5 or 10,10)
I found this example on how to create the array dynamically (for an int array):
int[,] myArray=new int[(int)s[0],(int)s[2]];
myArray[0, 0] = 2;
Console.WriteLine(myArray[0, 0]);
Console.ReadLine();
But I want to know how to create the elements "0" in my array dynamically.
Try this:
var r = 7;
var c = 4;
var outArr = new string[r, c];
for (var i = 0; i < r; i++)
for (var j = 0; j < c; j++)
outArr[i, j] = "0";
That gives me:

Categories