Tablice

darek963

Poniższa publikacja zawiera podstawowe informacje wraz z przykładami, które pozwalają na wykorzystanie tablic w języku C#. Artykuł nie wyczerpuje tematu.

Tablica to najprościej rzecz ujmując zestaw zaindeksowanych zmiennych tego samego typu. Początkujący programista może zapytać po co tablice skoro są zmienne? Taka struktura danych znajduje szerokie zastosowanie. Np jeśli chcemy w pamięci przechowywać nazwy dni tygodnia dużo wygodniej jest skorzystać z tablic zamiast ze zmiennych. Będą one przetrzymywane w strukturze o tej samej nazwie i będziemy mogli się do nich odwoływać po indeksie, który będzie reprezentował ich kolejność w kalendarzu.

1 Tablice jednowymiarowe
2 Tablice wielowymiarowe
3 Tablice postrzępione (jagged arrays)

Tablice jednowymiarowe

Deklaracja tablicy w języku C# wygląda następująco:

Kopiuj
typ_danych[] nazwa_tablicy; 

przykład:

Kopiuj
string[] dniTygodnia; 

Ten przykład zadeklarował nam tablicę, której elementy są typu string. Samo zadeklarowanie tablicy nie powoduje, że jest ona już gotowa do użycia (tak jak to bywa w niektórych językach). Należy ją teraz zainicjalizować:

Kopiuj
nazwa_tablicy = new typ_danych[liczba_elementów]; 

przykład:

Kopiuj
dniTygodnia = new string[7]; 

Mamy już gotową tablicę, w której możemy zapisywać wartości:

Kopiuj
nazwa_tablicy[indeks] = wartosc; 

przykład:

Kopiuj
dniTygodnia[0] = "poniedziałek";
dniTygodnia[1] = "wtorek";
dniTygodnia[2] = "środa";
dniTygodnia[3] = "czwartek";
dniTygodnia[4] = "piątek";
dniTygodnia[5] = "sobota";
dniTygodnia[6] = "niedziela"; 

Teraz ktoś może zapytać - a skąd to zero? Programując w C# należy pamiętać, że w tym środowisku wszystkie indeksy są tworzone od zera a nie od 1. Czyli deklarując tablicę dniTygodnia w powyższy sposób stworzyliśmy strukturę, której pierwszy element posiada indeks 0 a ostatni 6.

Deklarację i inicjalizację można połączyć i zapisać w jednej linii.

Kopiuj
string[] dniTygodnia = new string[7]; 

Kolejny sposób zapisu w jednej linii to deklaracja tablicy i przypisanie wartości. Tutaj nie trzeba jawnie zapisywać inicjalizacji:

Kopiuj
string[] dniTygodnia = { "poniedziałek", "wtorek", "śr", "cz", "pi", "so", "ni" }; 

Umiemy już deklarować i inicjalizować tablicę oraz zapisywać w niej wartości. Teraz czas pokazać jak odczytywać z niej dane. Poniższy kod tworzy zmienną i tablicę typu string oraz przypisuje do zmiennej pierwszą wartość z tablicy (o indeksie 0):

Kopiuj
string zmienna;
string[] dniTygodnia = { "poniedziałek", "wtorek", "śr", "cz", "pi", "so", "ni" };
zmienna = dniTygodnia[0]; 

W języku C# tablica to nie tylko struktura danych ale również obiekt, przez co posiada własne metody oraz właściwości. Dzięki temu korzystanie z tablic staje się jeszcze łatwiejsze. Np. żeby odczytać długość tablicy (liczbę elementów) możemy skorzystać z właściwości Length:

Kopiuj
int dlugoscTablicy;
dlugoscTablicy = dniTygodnia.Length; 

Podczas odczytywania lub zapisywania wartości w tablicach w nawiasach kwadratowych zamiast jawnej liczby można podać nazwę zmiennej, która będzie tego samego typu. Dzięki temu w łatwy sposób możemy np. odczytać interesujące nas elementy tablicy:

pierwsze 5:

Kopiuj
for (int indeks = 0; indeks < 5; indeks++)
{
Console.WriteLine( dniTygodnia[indeks] );
} 

wszystkie:

Kopiuj
for (int indeks = 0; indeks < dniTygodnia.Length; indeks++)
{
Console.WriteLine( dniTygodnia[indeks] );
} 

Operując na wszystkich elementach tablicy warto skorzystać z pętli FOREACH. Daje nam ona możliwość krótszego zapisu niż pętla FOR:

Kopiuj
foreach(string element in dniTygodnia)
{
Console.WriteLine(element);
} 

W powyższym przypadku pętla FOREACH wykona się tyle razy ile jest elementów w tablicy dniTygodnia. Podczas każdej iteracji pętli do zmiennej element będzie przypisany kolejny element tablicy.

Tablice wielowymiarowe

Tablice w języku C# mogą posiadać więcej niż jeden wymiar. Tzn. że każdy element może być reprezentowany przez więcej niż jeden indeks.

Wizualizacja tablicy jednowymiarowej:

0123456
poniedzialekwtorekśrczpisoni

Wizualizacja tablicy dwuwymiarowej:

0123456
0poniedzialekwtorekśrczpisoni
1mondaytuesdaywethfrsasu
2montagdienstagmidofrsaso

Deklaracja i inicjalizacja tablicy dwuwymiarowej, która będzie przechowywać nazwy dwóch pierwszych dni tygodnia w trzech językach:

Kopiuj
string[,] dniTygodnia;
dniTygodnia = new string[2, 3]; 

to samo można zapisać w jednej linii:

Kopiuj
string[,] dniTygodnia = new string[2, 3]; 

Przypisanie wartości do elementów tablicy dwuwymiarowej:

Kopiuj
dniTygodnia[0, 0] = "poniedzialek";
dniTygodnia[1, 0] = "wtorek";
dniTygodnia[0, 1] = "monday";
dniTygodnia[1, 1] = "tuesday";
dniTygodnia[0, 2] = "montag";
dniTygodnia[1, 2] = "dienstag"; 

Odczytywanie wartości elementu tablicy dwuwymiarowej:

Kopiuj
string zmienna;
zmienna = dniTygodnia[1, 1]; 

Wyświetlenie w konsoli nazw drugiego dnia tygodnia (indeks = 1) we wszystkich językach:

Kopiuj
for (int i = 0; i < 3; i++)
{
Console.WriteLine(dniTygodnia[1,i]);
} 

Wyświetlenie wszystkich elementów tablicy używając pętli FOREACH:

Kopiuj
foreach (string element in dniTygodnia) 
{ 
Console.WriteLine(element); 
} 

Aby sprawdzić ile wymiarów ma tablica należy posłużyć się właściwością Rank:

Kopiuj
int[,,] ary = new int[2, 4, 3];
Console.WriteLine(ary.Rank); // 3

Deklaracja tablicy typu prostego może wyglądać tak:

Kopiuj
int[] tab = new tab[10];

a jej użycie tak:

Kopiuj
tab[0]=20;

Jeżeli zechcemy użyć własną klasę:

Kopiuj
sigma
{
    int value;
    public void SETvalue(int a)
    {
        value = a;
    }
}

i zbudować tablicę wielowymiarową klas, to deklaracja:

Kopiuj
sigma[,] si = new sigma[2,5];

nie wystarczy. Trzeba jeszcze dla każdego pola tablicy utworzyć instancje klasy np. tak:

Kopiuj
si[0,0] = new sigma();

Dopiero wtedy można odwołać się do pola tablicy:

Kopiuj
si[0,0].SETvalue(5);

Tablice postrzępione (jagged arrays)

Elementami tablicy postrzępionej (ang. jagged array) są tablice. Przykład deklaracji takiej tablicy:
Kopiuj
int[][] ary = new int[3][];

ary[0] = new int[2];
ary[1] = new int[4];
ary[2] = new int[3];

ary[0][0] = 1;
ary[0][1] = 2;

ary[1][0] = 3;
ary[1][1] = 4;
ary[1][2] = 5;
ary[1][3] = 6;

ary[2][0] = 7;
ary[2][1] = 8;
ary[2][2] = 9;

Jak widzimy elementami tej tablicy są tablice, które zawierają po kolei 2, 4 i 3-elementy. Powyższy kod można zapisać krócej - od razu inicjalizując elementy, dzięki czemu nie trzeba podawać wymiaru tablicy:

Kopiuj
int[][] ary = new int[][]
{
    new int[2],
    new int[4],
    new int[3]
};
ary[0][0] = 1;
ary[0][1] = 2;

ary[1][0] = 3;
ary[1][1] = 4;
ary[1][2] = 5;
ary[1][3] = 6;

ary[2][0] = 7;
ary[2][1] = 8;
ary[2][2] = 9;

lub jeszcze prościej:

Kopiuj
int[][] ary =           // lub: int ary[][] = new int[][]
{
    new int[] {1,2},
    new int[] {3,4,5,6},
    new int[] {7,8,9}
};

Należy pamiętać, iż typy "podrzędnych" tablic muszą być takie same jak typ tablicy "głównej", przez co niemożliwy jest zapis np.:

Kopiuj
int[][] ary =
{
    new double[] {1.99, 2.88}, // <-- błąd konwersji int[] -> double[]
    new int[] {3,4,5,6},
    new int[] {7,8,9}
};

Jest to oczywiste, bo w końcu chodzi nam o tablicę intów.

Dostęp do tablic postrzępionych realizowany jest w postaci tablica[x][y], gdzie x to indeks elementu tablicy "głównej", a y - indeks tablicy, która znajduje się pod elementem x tablicy "głównej". Przykład dla zadeklarowanej wyżej tablicy ary:

Kopiuj
Console.Write(ary[1][2]); // 5

ponieważ:

1 2 // ary[0]
3 4 5 6 // ary[1]
7 8 9 // ary[2]

1 2
3 4 5 6</b> // ary[1][2]
7 8 9

Jeśli chodzi o właściwość Length, to:

Kopiuj
Console.Write("{0}; {1} {2}", ary.Length, ary[0].Length, ary[1].Length); // 3; 2 4

Oczywiście można też tworzyć bardziej zagnieżdżone wymiary:

Kopiuj
int[][][] ary =
{
    new int[][]
    {
        new int[] {1,2},
        new int[] {3,4,5}
    }
};
Console.Write(ary[0][1][2]); // 5

Również nic nie stoi na przeszkodzie, aby zadeklarować tablice wielowymiarowe:

Kopiuj
int[][,] ary =
{
    new int[,] { {1,2}, {3,4} },
    new int[,] { {5,6,7}, {8,9,10} }
};
Console.WriteLine(ary[1][0, 2]); // 7

Tablice postrzępione przydają się, kiedy różne wymiary mają mieć różną ilość elementów i/lub trzeba się do nich dostać nie znając wymiarów tablicy. Oto przykład:

Kopiuj
int[,] ary = new int[2, 3] { {1,2,3}, {4,5,6} };
for (int i = 0; i < 2; i++)
{
    for (int j = 0; j < 3; j++)
        Console.Write(" {0}", ary[i, j]);
    Console.WriteLine();
}

Wynik będzie następujący:

1 2 3
4 5 6

a co, jeśli chcielibyśby wyświetlić:

1 2 3
4 5

Tablicami wielowymiarowymi to już się tak prosto nie da, jedynym wyjściem będzie warunek w środku pętli, ale to bez sensu. Do tego możemy właśnie użyć jagged array:

Kopiuj
int[][] ary =
{
    new int[] {1,2,3},
    new int[] {4,5},
};
for(int i = 0; i < ary.Length; i++)
{
    for(int j = 0; j < ary[i].Length; j++)
        Console.Write("{0} ", ary[i][j]);
    Console.WriteLine();
}

5 komentarzy

Witam. Koledzy potrzebuje utworzyć tablicę 63 wiersze i 12 kolumn i wpisywać do niej dane w formie {1,2,3,4,5,6,7,8,9,10,11,12}. Tablicę zadeklarowałem jako:
int[,] tablicaA;
tablicaA = new int [63,12];
chyba dobrze ale nie jej wypełnić w formie podanej wyżej. Co robię źle?

Brakuje jeszcze opisu jak wyświetlić tablice dwuwymiarowe w Windows Forms.

Już nie brakuje ;]

"Teraz ktoś może zapytać - a skąd to zero? Programując w C# należy pamiętać, że w tym środowisku wszystkie indeksy są tworzone od zera a nie od 1." Trochę niefortunne stwierdzenie, bo w większości (jeśli nie we wszystkich) języków tak jest.

BTW. Dobry tekst

Artykuł OK, choć brakuje opisu tablic postrzępionych (jagged array). A i dodaj artykuł też do podręcznika.
Pozdrawiam.