Kontynuacją notatki opisującej podstawy pracy z tablicami są tablice wielowymiarowe. C# udostępnia dwa rodzaje tablic wielowymiarowych: tablice nieregularne oraz tablice prostokątne.
Tablice nieregularne to nic innego jak tablica tablic. Zasady dotyczące deklaracji tablic wielowymiarowych nie zmieniają się w stosunku do deklaracji tablic jednowymiarowych. W przykładzie poniżej przygotujemy tablicę nieregularną. Celem będzie odszukanie największej wartości na poziomie każdej tablicy oraz w całej strukturze. W przypadku deklaracji tablicy o określonym wymiarze bez podawania wartości elementów, tworzona tablica automatycznie dla wszystkich elementów ustawia wartość domyślną dla określonego typu wartościowego. Tablica nieregularna zadeklarowana w ten sposób var arraysNull = new int[4][];
będzie zawierać 4 null'e. Poniżej deklarujemy typ tablicowy zawierający tablicę wartości typu int
, pamiętając o możliwości pojawienia się braku referencji do tablicy.
using System;
namespace HelloWorld
{
public static class Program
{
public static void Main()
{
var arrays = new int[][] {
new[] { 1, 2 },
new[] { 1, 2, 3, 4, 5, 6 },
null,
new[] { 1, 2, 3 }
};
Console.WriteLine("Number of tables: {0}", arrays.Length);
int max = 0;
for (int idxTable = 0; idxTable < arrays.Length; idxTable++)
{
if(arrays[idxTable] == null)
{
Console.WriteLine("Table {0} is null", idxTable);
continue;
}
int maxTable = 0;
for(int idxValue = 0; idxValue < arrays[idxTable].Length; idxValue++)
{
if (arrays[idxTable][idxValue] > maxTable)
maxTable = arrays[idxTable][idxValue];
}
if (maxTable > max)
max = maxTable;
Console.WriteLine("Table {0} contains {1} values. Max value is {2}", idxTable, arrays[idxTable].Length, maxTable);
}
Console.WriteLine("Max value in all tables is {0}", max);
Console.ReadLine();
}
}
}
Do tej pory nie korzystaliśmy z właściwości Length
, która zwraca rozmiar tablicy. W przypadku tablic przekraczających rozmiar int
możemy użyć właściwości LongLength
, zwracającej rozmiar typu long
. Korzystając z pętli, przechodzimy przez wszystkie tablice, zaczynając od sprawdzenia, czy nie są null'owe. Warunek wykonania pierwszej pętli określa wspomniana właściwość arrays.Length
. Następnie iterujemy elementy tablicy, gdzie liczbę elementów odczytujemy poprzez użycie arrays[idxTable].Length
. Zmienna idxTable
wskazuje na numer przeglądanej tablicy, a Length
zwraca jej rozmiar.
Do opisania zostały wspomniane tablice prostokątne, w których używamy tylko jednej pary nawiasów kwadratowych, niezależnie od liczby wymiarów. Liczbę wymiarów określamy poprzez liczbę przecinków umieszczonych pomiędzy nawiasami. Tablica prostokątna to tak naprawdę jedna duża tablica (zwróć uwagę na wartość zwróconą przez Length
). W przeciwieństwie do tablicy nieregularnej wymiarów nie deklarujemy poprzez new
. Sposób uzyskania wartości elementu nie różni się znacząco od standardowej tablicy, w nawiasach kwadratowych podajemy pozycję w kolejnych wymiarach. Alternatywnie możemy użyć metody GetValue
, gdzie również podajemy lokalizację elementu. Pamiętajmy, że pierwszy element tablicy posiada indeks o numerze 0. W przykładzie poniżej ponownie spróbujemy uzyskać największą wartość znajdującą się w tablicy. W pierwszym podejściu użyjemy kilku zagnieżdżonych pętli, tak aby zapewnić iterację po wszystkich wymiarach. Metoda GetLength
zwraca rozmiar wymiaru. Drugi sposób wykorzystuje fakt, że jest to jedna duża tablica. Do przejścia po wszystkich elementach została użyta pętla foreach
.
using System;
namespace HelloWorld
{
public static class Program
{
public static void Main()
{
int[,,] arraysTwo = new int[,,]
{
{
{ 1, 2, 3, 4, 5 },
{ 4, 5, 6, 7, 8 },
{ 7, 8, 9, 0, 1 },
},
{
{ 7, 8, 9, 0, 1 },
{ 0, 1, 99, 3, 4 },
{ 3, 4, 5, 6, 9 },
},
};
Console.WriteLine("arraysTwo length = {0}", arraysTwo.Length);
Console.WriteLine("arraysTwo[0, 2, 4] = {0}", arraysTwo[0, 2, 4]);
Console.WriteLine("arraysTwo.GetValue(1, 1, 2) = {0}", arraysTwo.GetValue(1, 1, 2));
int maxFor = 0;
for (int level0 = 0; level0 < arraysTwo.GetLength(0); level0++)
for (int level1 = 0; level1 < arraysTwo.GetLength(1); level1++)
for (int level2 = 0; level2 < arraysTwo.GetLength(2); level2++)
if (arraysTwo[level0, level1, level2] > maxFor)
maxFor = arraysTwo[level0, level1, level2];
Console.WriteLine("maxFor = {0}", maxFor);
//----------------------------------
int maxForeach = 0;
foreach (var i in arraysTwo)
if (i > maxForeach)
maxForeach = i;
Console.WriteLine("maxForeach = {0}", maxForeach);
Console.ReadLine();
}
}
}
Warto wspomnieć, że próba zmiany "prostokątnego" kształtu tablicy, poprzez wprowadzenie nieregularności (zmiana liczby elementów w wierszu) zostanie zgłoszona jako błąd przez kompilator.
Na koniec załóżmy, że projektanci języka C# nie przygotowali tablicy prostokątnej. Twoim zadaniem jest zaprojektowanie metody GetValue, tak aby umożliwić dostęp do wartości trójwymiarowej tablicy (identycznej jak w wcześniej omówionym przykładzie). Poniżej zamieszczam kod. Zaimplementuj metodę GetValue tak, aby zwróciła wartość z lokalizacji [1, 1, 2], wielowymiarowej tablicy składającej się z 3 wierszy oraz 5 kolumn.
using System;
namespace HelloWorld
{
public static class Program
{
private static int[] arraysTwo = {
1, 2, 3, 4, 5,
4, 5, 6, 7, 8,
7, 8, 9, 0, 1,
7, 8, 9, 0, 1,
0, 1, 99, 3, 4,
3, 4, 5, 6, 9};
public static void Main()
{
var result = GetValue(1, 1, 2);
Console.WriteLine("GetValue(1, 1, 2) = {0}", result);
Console.ReadLine();
}
public static int GetValue(int x, int y, int z)
{
//TODO
return 0;
}
}
}
/// <summary>
/// Zwraca wartość elementu "kwazi" prostokątnej tablicy [x,y,z]
/// </summary>
/// <param name="x">Indeks pierwszego wymiaru (grupa)</param>
/// <param name="y">Indeks drugiego wymiaru (wiersz)</param>
/// <param name="z">Indeks trzeciego wymiaru (kolumna)</param>
public static int GetValue(int x, int y, int z)
{
return arraysTwo[(5 * 3 * x) + (5 * y) + z];
}
x
określa indeks grupy, przejście do kolejnej grupy to przesunięcie się o 3 wiersze, gdzie każdy z nich zawiera 5 kolumn.y
określa indeks wiersza, przejście do kolejnego wiersza to przejście o 5 kolumn.z
określa indeks kolumny.