C# - How to add values to a 3D array? - c#

I'm building an interactive map using Mapbox and would like to draw a polygon over a specific area like is shown here. For this I need to dynamically fill a 3D array with the X,Y and Z coordinates from a database. The array structure I want to achieve is:
[
[
[
[xCoordinate1, yCoordinate1, zCoordinate1],
[xCoordinate2, yCoordinate2, zCoordinate2],
[xCoordinate3, yCoordinate3, zCoordinate3]
]
]
]
I have been trying to accomplish this with C#. In my application I initialized a 3D list, like so:
List<List<List<List<double>>>> coordinates = new List<List<List<List<double>>>>();
Next I iterated over the coordinates that are coming from the database so they would be added to the array:
foreach (var coordinate in Coordinates) {
coordinates.Add({ coordinate.X, coordinate.Y, coordinate.Z })
}
However this doesn't add the values at the disired position and throws an IndexOutOfBounds exception. I have also tried to initialize the array, like so:
double[, , ,] coordinates = {
{
{
{ coordinate.X, coordinate.Y, coordinate.Z },
{ coordinate.X, coordinate.Y, coordinate.Z },
{ coordinate.X, coordinate.Y, coordinate.Z }
}
}
};
With this approach i was also unable to format my array the way it should be formatted. Can someone show me how to work with a complex 3D array so that it gets the structure I'm looking for?
To sum up:
int[,,,] array3D = new int[,,,] {
{
{
{ 1, 2, 3 },
{ 4, 5, 6 }
//How can I add more here dynamically?
}
}
};
array3D[0, 0, 0, 3] = { 7, 8, 8 }; //This doesn't do the trick :(

You cannot change the size of a multidimensional array, but that is ok because your JSON really represents an array of arrays of sorts.
Start with the (expandable) list of coordinates
var coords = new List<double[]>
{
new double[] { 1,2,3 },
new double[] { 4,5,6 },
};
// later
coords.Add(new double[] { 7, 8, 9 });
Then convert to the JSON structure for export. You showed an array of array of array of coordinates (array).
var json = new double[][][][] {
new double[][][] {
coords.ToArray()
}
};
This is how you recover the coordinates
foreach (var item in json[0][0])
{
Debug.WriteLine($"Point=({item[0]}, {item[1]}, {item[2]})");
}
In the output window, you see
// Point=(1, 2, 3)
// Point=(4, 5, 6)
// Point=(7, 8, 9)

If I understand correctly, you can get away with just 2D list, where the first list contains sets of coordinates (i.e. (x,y,z)) and the second list simply contains a bunch of first lists, like so:
List<List<double>> coords = new List<List<double>>();
coords.Add(new List<double> { 24, 54, 46 });
coords.Add(new List<double> { 32, 45, 48 });
Console.WriteLine(coords[1][1]);
//Outputs 45.
//Note: xCoord = 24, yCoord = 54, zCoord = 46 in the first list entry
You can make it a separate method or an extension method where the coordinates are passed in as an arguments. It's also possible to loop through the lists to get particular x,y or z coordinate (if you need to search through them in your code).

Related

How do I initialize a list<> with two dimensional arrays?

List<int[,]> table = new List<int[,]> { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
This isn't right, but I'm stumped on how to do it.
Basically in the end I want to say table[0] and get back the first tuple, table[2] and get back the second tuple, and so on.
What is the correct format (if I have the right data model) or the correct data structure for what I want to do?
I have a pretty hefty list of tuples in the above format, And I like to stay with the format if at all possible.

How to build up the observation array in Accord.NET using C#

I'm trying to learn the ropes in Accord.NET and AI world...
The goal is clustering a list of Customers using the K-Means algorithm.
For each Customer, I got three features:
CustomerID, ProductCategory, TotQty, TotAmount
AAA, 01, 50, 3000
AAA, 02, 10, 150
BBB, 01, 45, 2700
...
Now, I have to pass the observations to K-Means algorithm:
double[][] observations = ... (?)
// Create a new K-Means algorithm
KMeans kmeans = new KMeans(k: 10);
// Compute and retrieve the data centroids
var clusters = kmeans.Learn(observations);
// Use the centroids to parition all the data
int[] labels = clusters.Decide(observations);
First Question: Do I have to group the data by Customer? Like this:
double[][] observation =
{
new double[] { 1, 50, 3000, 2, 10, 150 },
new double[] { 1, 45, 2700}
}
or:
double[][] observation =
{
new double[] { 1, 50, 3000},
new double[] { 2, 10, 150},
new double[] { 1, 45, 2700}
}
Second Question: how I trace back the result to the original CustomerID?
I mean as soon as I got the result with the assigned Label int[] labels = clusters.Decide(observations); how I can determine which Customer belongs to which Cluster/Label?
I made Generic K-means Library for c#
so you can use it for your second question. (After you got centroid you can get objects that belong to that centroid)
https://github.com/pashkovdenis/K-means/

Multi Label Support Vector Machine in Accord.NET

I am trying to make a Multi Label Support Vector Machine using Accord.NET framework (MultilabelSupportVectorMachine Class) but based on the example it's difficult to understand the encoding e.g.:
// Sample input data
double[][] inputs =
{
new double[] { 0 },
new double[] { 3 },
new double[] { 1 },
new double[] { 2 },
};
// Outputs for each of the inputs
int[][] outputs =
{
new[] { -1, 1, -1 },
new[] { -1, -1, 1 },
new[] { 1, 1, -1 },
new[] { -1, -1, -1 },
};
What if my output is a matrix which contains integer values not within the -1 and +1 range, what encoding should we use to convert the data into this format?
This is the format of the output the MultiLabelSupportVectorMachine would return if you compute something with it. MultiClassSupportVectorMachine returns a single int because it is used when you are sure that an example matches only a single class whereas MultiLabelSupportVectorMachine returns an array which shows which classes does the example match and is used when an example can match more classes.
It works like this:
The output array length is between 0(inclusive) and the number of classes. So if you have 4 classes you'll have an output array like this:
{ -1, -1, 1, -1 }
This means that the output class is 2, because the index of 1 is 2.
I hope that now you know how the output of this class works and that this gives you directions how to format your example output.
Additional info: If you want to use MultiLabelSupportVectorMachine, but you want to get only one output class you can just take the first index of 1 in the output array. I recommend this only if you are certain that One-Vs-All serves you better than One-Vs-One.

How convert a list to int[][]

I have a class piece where I define each piece shape.
myShape.Add(new piece
{
Height = 3,
Width = 2,
Name = "3x2 L TopRight",
Size = 4,
Shape = new int[][] {
new int[] { 1, 0 },
new int[] { 1, 0 },
new int[] { 1, 1 }
}
});
But I create those shape by hand, now I reading the pieces in real time, so I create something like
List<int[]> virtualRow = new List<int[]>();
virtualRow.Add(new int[] { 1, 0 });
virtualRow.Add(new int[] { 1, 0 });
virtualRow.Add(new int[] { 1, 1 });
So how can I create Shape using virtualRow ?
I try something like
Shape = new int[][] { virtualRow.ToArray() }
But say
Cannot implicitly convert type 'int[][]' to 'int[]'
virtualRow.ToArray() is already an array of array of int values. You don't need to create a new array of array of ints and add this to it.
All you need is:
Shape = virtualRow.ToArray(),
virtualRow is a List of integer arrays, so to get an array of integer arrays you simply write:
Shape = virtualRow.ToArray();
...the return type of List.ToArray() being T[] as required.
Your code is in error because it attempts to add an int[][] to Shape instead of creating Shape as an int[][].
You want to do the following:
Shape = virtualRow.ToArray();
Since virtualRow is already a list of arrays. The ToArray function creates an int[][] object for your virtualRow, and all you need to do is store it to shape. What you were trying to do was create a matrix, within which was the result of the ToArray function. This way you are just storing the result of the function which gives you what you want.

Create 3 dimensional array

I'm new at C# and I want to create a multidimensional array like this:
(source: parks.ca.gov)
But in 8x8x4 cells.
I want to store maze cells.
{
{1,1,1,0}, {1,0,0,0}, {1,1,1,1}, {1,0,0,0}, {1,1,0,1}, {1,1,0,1}, {0,1,0,0}, {1,0,0,1},
...
{0,1,1,0}, {1,0,1,0}, {0,0,1,1}, {1,0,1,0}, {1,0,0,1}, {0,1,0,1}, {1,1,1,0}, {1,1,0,1},
}
int[,,] table = new int[8,8,4]; // is this right?
table[0,0] = {0, 0, 1, 1}; // I want to fill it this way.
I'm aware it does not explicitly answer the question, but in my opinion you're shooting yourself in the foot by working with 3D arrays. C# is an OO language, so it really helps if you think OO.
Instead of working with a multidimensional array representing cells for you 3d Maze (if it is really a 3d maze you want), why not create a List of classes named Cell, each one containing their position and other stuff you need, like :
public class Cell
{
public Cell (int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public bool IsExplored { get; set; }
}
Then you can have a simple List<Cell> that you can iterate over.
You can also remove the x,y,z and create a Position class.
For walls, you can create an Enum and use bitwise operations, or store a list of Enum. Since you're a beginner, I'd suggest you the list of enums. You would have to add this Enum in the code, and this property to the Cell class :
public Enum WallPosition
{
Top,
Left,
Bottom,
Right
}
public List<WallPosition> walls { get; set;} //This goes into the Cell class
That way, every operation will be much much easier to do. For example, if you need to explore every cell at the column #3, you can do
foreach (Cell cell in yourCellList.Where(c => c.Y == 3))
{
cell.IsExplored = true;
}
Need to render every explored cell differently?
foreach (Cell cell in yourCellList.Where(c => c.IsExplored) { //Do stuff }
And so on.
No need for complicated for loops with your 3 dimensions, and a simple foreach is in my opinion far more readable than a
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
for (int k = 0; k < 4; k++)
every time you need to access your table.
The only ugly part would be to fill you list (By creating new Cell instances), but it would still be far more readable than a huge wall of { { { 0, 1, 0, 1 }, {1, 1, 1, 0} [...]
I'd also suggest that you read an introduction to OO principles.
With multidimensional arrays, you can either set them all at once (using basically the syntax you showed):
int[,,] table = {
{ { 1, 1, 1, 0 }, { 1, 0, 0, 0 } },
{ { 0, 1, 1, 0 }, { 1, 0, 1, 0 } }
};
or you can set the items one by one:
int[,,] table = new int[8,8,4];
table[0,0,0] = 0;
there is nothing in between. The best you could do is to write an extension method that would work something like this:
table.Set(0, 0, new int[] { 0, 0, 1, 1 });
As an alternative, you could use 2D array of arrays:
int[,][] table = {
{ new[] { 1, 1, 1, 0 }, new[] { 1, 0, 0, 0 } },
{ new[] { 0, 1, 1, 0 }, new[] { 1, 0, 1, 0 } }
};
or you could use almost the syntax you proposed:
int[,][] table = new int[8,8][];
table[0,0] = new[] { 0, 0, 1, 1 };
A disadvantage of this approach is that it doesn't force the inner arrays to be all the same length.
As proposed in comments, another option would be use a custom type like Cell and have a 2D array of those. Doing that makes it clearer what the array actually means, table[0,0].Left is certainly more readable than table[0,0,1].
If the wall can be there or not, you shouldn't use int values 0 and 1, you should use bool values false and true. If you want to have more states, an enum might be appropriate.
Your structure contains a lot of duplication, since bottom of a cell is the same as top of the cell below it (unless you want to have one way walls). This means the structure can get into an inconsistent state, which is often hard to debug (“The wall isn't there? But I just looked and it is there.”).
One way to avoid that would be store walls instead of cells. Instead of 8×8 cells, you would have 8×9 horizontal walls and 9×8 vertical walls. You could then have methods that would abstract this away, so you could easily look up walls of a particular cell.
An array initializer for a 3D array would look like this:
int[,,] table = {
{ {1,1,1,0}, {1,0,0,0}, ... },
{ {0,1,1,0}, {1,0,1,0}, ... },
...
};
The first line is right. The second line won't work. The closest thing is to use a 2D array of arrays:
int[,][] table = new int[8,8][];
table[0,0] = new int[] {0, 0, 1, 1};
Like #tigrou and #Pierre-Luc Pineault suggested, it would be a lot cleaner to encapsulate each cell in an object instead of a plain array.
Consider storing the data in an external file and reading it in instead of hardcoding the 256 numbers.

Categories