From #Henk Holterman's response regarding C# 3 dimensional arrays (answered Mar 29 '09 at 12:05), how do you print foos to the console:
Foo[][][] foos = new Foo[2][][];
for (int a = 0; a < foos.Length; a++)
{
foos[a] = new Foo[3][];
for (int b = 0; b < foos[a].Length; b++)
{
foos[a][b] = new Foo [4];
for (int c = 0; c < foos[a][b].Length; c++)
foos[a][b][c] = new Foo();
}
}
Thanks.
This is fairly simple to do. Use three for statements to loop through each indexer to get to each instance of Foos.
for (int x = 0; x < foos.Length; x++) {
for (int y = 0; y < foos[x].Length; y++) {
for (int z = 0; z < foos[x][y].Length; z++) {
Console.WriteLine(foos[x][y][z].Member);
}
}
}
Related
I'm getting the error that the index for my array is out of range.
I define a 3D array like this:
Button[, ,] posAr_ItemManager = new Button[maxRows, maxColumns, maxCategories];
Where maxRows, maxColumns and maxCategories are all constant integers.
I then want to loop through this whole array, i do it using nested loops as shown here:
for (int i = 0; i < posAr_ItemManager.GetLength(0); i++)
{
for (int j = 0; i < posAr_ItemManager.GetLength(1); j++)
{
for (int z = 0; i < posAr_ItemManager.GetLength(2); z++)
{
if (posAr_ItemManager[i,j,z] != null)
{
Button but = posAr_ItemManager[i, j, z];
but.Width = itemWidth;
but.Height = itemHeight;
but.SetValue(Canvas.LeftProperty, itemPanelX + (i + 1) * butSpacing + i * itemWidth);
but.SetValue(Canvas.TopProperty, itemPanelY + (i+1)*butSpacing + i* itemHeight);
}
}
}
}
When I run the program it gives the out of range error where I check if the item is not equal to null.
I have no idea why it does it as I thought my declaration of the 3D array is correct and the nested loop as well? thanks in advance!
for (int i = 0; i < posAr_ItemManager.GetLength(0); i++)
{
for (int j = 0; j < posAr_ItemManager.GetLength(1); j++)
{
for (int z = 0; z < posAr_ItemManager.GetLength(2); z++)
look very carefully at the middle tests. Also, consider hoisting the GetLength tests so you only do them once per dimension. Perhaps:
int rows = posAr_ItemManager.GetLength(0), columns = posAr_ItemManager.GetLength(1),
categories = posAr_ItemManager.GetLength(2);
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < columns; col++)
{
for (int cat = 0; cat < categories; cat++)
You're using "i" to check if the loop is over in each of the dimensions. Change it to corresponded i,j,z.
for (int i = 0; i < posAr_ItemManager.GetLength(0); i++)
{
for (int j = 0; **j** < posAr_ItemManager.GetLength(1); j++)
{
for (int z = 0; **z** < posAr_ItemManager.GetLength(2); z++)
I got the following codes:
Boo[,,] boos = new Boo[8, 8, 8];
Boo GetMe(int i, int j, int k)
{
return boos[i, j, k];
}
The code above is inefficient so i convert it to one dimensional array:
Boo[] boosone;
Boo[,,] boos = new Boo[8, 8, 8];
Boo GetMe(int i, int j, int k)
{
if (boosone == null)
{
boosone = new Boo[8 * 8 * 8];
int num = 0;
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
for (int z = 0; z < 8; z++)
{
boosone[num] = boos[x, y, z];
num++;
}
}
}
}
return boosone[?];
}
How can I get the Boo (from the same position like in multidimensional array j k l) from the one dimensional array boosone?
int index = (8 * 8 * i) + (8 * j) + k;
return boosone[index];
Not really sure why you're saying that the first 3D array is not efficient (I mean, have you actually noticed a particularly heavy slowdown when using it?), but you can do that with some simple offset calculations.
First of all, if you target the latest C# version, you can replace the whole copy function with just two lines, and your code would then look like this:
using System;
using System.Runtime.InteropServices;
Boo[] boosone;
Boo[,,] boos = new Boo[8, 8, 8];
Boo GetMe(int i, int j, int k)
{
if (boosone == null)
{
boosone = new Boo[boos.Length];
MemoryMarshal.CreateSpan(ref boos[0, 0, 0], boosone.Length).CopyTo(boosone);
}
return boosone[boos.GetLength(1) * boos.GetLength(2) * i + boos.GetLength(2) * j + k];
}
If you don't want to use the MemoryMarshal class for some reason, you could also use LINQ to flatten your 3D array, although this approach is much less efficient:
boosone = boos.Cast<Boo>().ToArray();
Accessing a multi dimensional array isn't any slower then accessing a single dimension array, in fact they are both stored in memory exactly the same way. It's not what you are doing, it's how you are doing it.
If you want to wrap either array in a trivial method, give the compiler a hint that it can be inline
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Boo GetMe(int i, int j, int k)
{
return boos[i, j, k];
}
On saying that, this method does absolutely nothing and has no advantage then just using the array indexer.
If you want to work with segments of an array with out the overhead of reallocation, consider using Span<T> or Memory<T> or ArraySegment
At about this point I would write example code, however as I have no idea what you are doing, it's hard to guess what you need.
What I suggest, is download BenchmarkDotNet, and start profiling your code to work out what is the most efficient and performant way to do what you desire, don't guess...
Why don't you look at jagged arrays which provide better performance? I did a test (under RELEASE configuration) which showed that you wrapper is twice faster than the d3 array, but jagged is 3 times faster than the d3 array.
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace ArrayWrapper
{
class ArrayPerformanceTest
{
int xSize = 2;
int ySize = 3;
int zSize = 4;
int count = 100000000;
int delay = 500;
static void Main(string[] args)
{
new ArrayPerformanceTest().Run();
}
private void Run()
{
var d3Array = CreateD3Array();
var wrapped = GetD1Adapter(d3Array);
var jagged = GetJaggedArray(d3Array);
Thread.Sleep(delay);
TestD3Array(d3Array);
Thread.Sleep(delay);
TestWrappedArray(wrapped);
Thread.Sleep(delay);
TestJaggeddArray(jagged);
Thread.Sleep(delay);
}
private int[,,] CreateD3Array()
{
var rectangular = new int[xSize, ySize, zSize];
int i = 7;
for (var x = 0; x < xSize; x++)
for (var y = 0; y < ySize; y++)
for (var z = 0; z < zSize; z++)
rectangular[x, y, z] = ++i;
return rectangular;
}
private int[] GetD1Adapter(int[,,] d3Array)
{
return d3Array.Cast<int>().ToArray();
}
private int[][][] GetJaggedArray(int[,,] d3Array)
{
var xSize = d3Array.GetUpperBound(0) + 1;
var ySize = d3Array.GetUpperBound(1) + 1;
var zSize = d3Array.GetUpperBound(2) + 1;
var jagged = new int[xSize].Select(j => new int[ySize].Select(k => new int[zSize].ToArray()).ToArray()).ToArray();
for (var x = 0; x < xSize; x++)
for (var y = 0; y < ySize; y++)
for (var z = 0; z < zSize; z++)
jagged[x][y][z] = d3Array[x, y, z];
return jagged;
}
private void TestD3Array(int[,,] d3Array)
{
int i;
var sw = new Stopwatch();
sw.Start();
for (var c = 0; c < count; c++)
for (var x = 0; x < xSize; x++)
for (var y = 0; y < ySize; y++)
for (var z = 0; z < zSize; z++)
i = d3Array[x, y, z];
sw.Stop();
Console.WriteLine($"{nameof(d3Array),7} {sw.ElapsedTicks,10}");
}
private void TestWrappedArray(int[] wrapped)
{
int i;
var sw = new Stopwatch();
sw.Start();
for (var c = 0; c < count; c++)
for (var x = 0; x < xSize; x++)
for (var y = 0; y < ySize; y++)
for (var z = 0; z < zSize; z++)
i = wrapped[x * ySize * zSize + y * zSize + z];
sw.Stop();
Console.WriteLine($"{nameof(wrapped),7} {sw.ElapsedTicks,10}");
}
private void TestJaggeddArray(int[][][] jagged)
{
int i;
var sw = new Stopwatch();
sw.Start();
for (var c = 0; c < count; c++)
for (var x = 0; x < xSize; x++)
for (var y = 0; y < ySize; y++)
for (var z = 0; z < zSize; z++)
i = jagged[x][y][z];
sw.Stop();
Console.WriteLine($"{nameof(jagged),7} {sw.ElapsedTicks,10}");
}
}
}
Output:
d3Array 15541709
wrapped 8213316
jagged 5322008
I also analysed CPU usage.
It is of the same rate for all 3 approaches.
Here's my code
public int[,] GetBigEyeRoad(int x)
{
int[,] arrayBigEyeResult = new int[6, x];
Array.Copy(arrayBigEyeRoad, arrayBigEyeResult, arrayBigEyeRoad.GetLength(0) * arrayBigEyeRoad.GetLength(1));
return arrayBigEyeResult;
}
And calling it on my main class like this
int[,] arrayBigEyeRoad = bsb.GetBigEyeRoad(104);
string s = "";
for (int y = 0; y < arrayBigEyeRoad.GetLength(0); y++)
{
for (int x = 0; x < arrayBigEyeRoad.GetLength(1); x++)
{
s += string.Format("{0:D2}", arrayBigEyeRoad[y, x]);
s += ".";
}
s += "\n";
}
Debug.Log(s);
Here on this part
int[,] arrayBigEyeRoad = bsb.GetBigEyeRoad(104);
I only want to display 12 2D array values just like this
int[,] arrayBigEyeRoad = bsb.GetBigEyeRoad(12);
The problem is that it won't let me . Because it will give me an error saying
Destination array was not long enough. Check destIndex and length, and the array's lower bounds
Now how can I possible do it something like this
Limit the 2d display on the console
Pretty simple:
int[,] a1 = new int[100,200];
int[,] a2 = new int[10,5];
for (int i = 0; i < 10; i++)
for (int j = 0; j < 5; j++)
a2[i,j] = a1[i,j];
or
public class MyArray : int[,]
{
public override string ToString()
{
string result = "";
for (int i = 0; i < 10; i++)
for (int j = 0; j < 5; j++)
result += (a1[i,j].ToString() + ",");
return result;
}
}
static void Main(string[] args)
{
Random r = new Random();
int[,] x = new int[10,8];
int[] temp = new int[x.Length];
// two dimensional array and i want for three dimensional array
for(int i = 0; i < temp.Length; i++)
{
temp[i] = r.Next(10, 100);
for(int j = 0; j < i; j++)
{
if(temp[i] == temp[j])
{
i--;
break;
}
}
}
for(int i = 0, index = 0; i < x.GetLength(0); i++)
{
for(int j = 0; j < x.GetLength(1); j++)
{
x[i, j] = temp[index++]; //two dimensional array unique numbers
Console.Write(x[i, j] + " ");
}
}
// i want do it as for 3D and 4 D array unique numbers like that method what can i change or add?
It's pretty straight forward to do what you're doing for higher dimensions.
Here's my code for 3D:
var r = new Random();
int [,,] x = new int[10, 8, 8];
var count =
Enumerable
.Range(0, x.Rank)
.Select(y => x.GetLength(y))
.Aggregate((y, z) => y * z);
var values =
Enumerable
.Range(10, count)
.OrderBy(y => r.Next())
.ToArray();
var v = 0;
for (var i = x.GetLowerBound(0); i <= x.GetUpperBound(0); i++)
for (var j = x.GetLowerBound(1); j <= x.GetUpperBound(1); j++)
for (var k = x.GetLowerBound(2); k <= x.GetUpperBound(2); k++)
x[i, j, k] = values[v++];
To change it to 4D these lines change:
int [,,,] x = new int[10, 8, 8, 12];
// ...
var v = 0;
for (var i = x.GetLowerBound(0); i <= x.GetUpperBound(0); i++)
for (var j = x.GetLowerBound(1); j <= x.GetUpperBound(1); j++)
for (var k = x.GetLowerBound(2); k <= x.GetUpperBound(2); k++)
for (var l = x.GetLowerBound(3); l <= x.GetUpperBound(3); l++)
x[i, j, k, l] = values[v++];
Now, in this code I have explicitly called GetLowerBound as well as GetUpperBound as it is possible in .NET code to have a non-zero based array.
Also, rather than repeatedly re-try getting random numbers until you have unique numbers I simply generated a sequence of unique numbers and then randomly sorted them. That's a little different from your original code. You needed 80 (10 x 8) random values and you were choosing from values ranging from 10 to 99 inclusive. So you had some holes in your numbers.
Random r = new Random();
int[,,] x = new int[10, 8, 8];
int[] temp = new int[x.Length];
#region one dimensional array unique numbers.
for (int i = 0; i < temp.Length; i++)
{
temp[i] = r.Next(10, 650);
for (int j = 0; j < i; j++)
{
if (temp[i] == temp[j])
{
i--;
break;
}
}
}
#endregion
for (int i = 0, index = 0; i < x.GetLength(0); i++)
{
for (int j = 0; j < x.GetLength(1); j++)
{
for (int k = 0; k < x.GetLength(2); k++)
{
x[i, j, k] = temp[index++];
Console.Write(x[i, j, k] + " ");
}
Console.WriteLine();
}
}// i think it's correct code i've changed it
field = new int[input.Width][][];
for (int x = 0; x < input.Width; x++)
{
field[x] = new int[input.Height][];
for (int y = 0; y < 3; y++)
{
field[x][y] = new int[3];
}
}
For some reason the above code is giving me out of range exception but the following works fine:
field = new int[input.Width][][];
for (int x = 0; x < input.Width; x++)
{
field[x] = new int[input.Height][];
}
for (int y = 0; y < input.Height; y++)
{
for (int x = 0; x < input.Width; x++)
{
field[x][y] = new int[3];
field[x][y][0] = random.Next(0, output.Width);
field[x][y][1] = random.Next(0, output.Height);
field[x][y][2] = MaskFunctions.DSCALE;
}
}
Can anyone point out what am i doing wrong?
Also: Is there a difference between out of range and out of bound exception?
Your inner loop goes from 0 to 3, instead of 0 to input.Height. This will produce an out of range exception when input.Height < 3.
You probably meant to do this:
field = new int[input.Width][][];
for (int x = 0; x < input.Width; x++)
{
field[x] = new int[input.Height][];
for (int y = 0; y < input.Height; y++)
{
field[x][y] = new int[3];
}
}