Elementele unui șir pot avea orice tip; nu ne împiedică nimic să facem în așa fel ca aceste elemente să fie, la rândul lor, șiruri.
Pentru un șir de numere întregi, tipul elementelor este int, iar tipul șirului este int[]. Dar, dacă tipul elementelor ar fi int[], atunci tipul șirului ar trebui obținut prin adăugarea unei perechi de paranteze drepte: int[][]. Declarația ar arăta astfel:
1 |
int[][] a; |
Pentru a da o valoare șirului de șiruri, ar trebui să folosim new, apoi tipul elementelor șirului ( int[]), iar apoi numărul elementelor între paranteze drepte. De exemplu, dacă am vrea să avem un șir format din 10 șiruri, ne-am aștepta să scriem:
1 |
a = new int[][10]; |
Nu va funcționa... Trebuie invers! Vom vedea puțin mai încolo de ce. Instrucțiunea corectă este:
1 |
a = new int[10][]; |
Pentru a accesa primul șir din șirul nostru de șiruri am scrie a[0]; a[0] este un șir. Nu este greu să ne dăm seama că pentru a accesa primul element al șirului a[0] va trebui să scriem a[0][0].
Dar, a[0] nu conține deocamdată nimic. Să presupunem că el ar trebui să fie un șir format din 10 numere întregi. Pentru a crea acest șir, va trebui să scriem:
1 |
a[0] = new int[10]; |
De-abia acum putem lucra cu elemente de genul a[0][0].
Matrice
Cel mai simplu șir de șiruri este matricea. Aceasta poate fi privită ca fiind o grilă cu un anumit număr de linii și un anumit număr de coloane.
Fiecare linie este un șir (cu un număr de elemente egal cu numărul coloanelor), iar matricea este un șir de linii. Un exemplu este:
1 2 3 |
1 2 3 4 5 6 7 8 9 10 11 12 |
Avem o matrice cu trei linii și patru coloane; dacă dorim să creăm matricea element cu element, am putea scrie următorul cod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int[][] matrice = new int[3][]; matrice[0] = new int[4]; matrice[1] = new int[4]; matrice[2] = new int[4]; matrice[0][0] = 1; matrice[0][1] = 2; matrice[0][2] = 3; matrice[0][3] = 4; matrice[1][0] = 5; matrice[1][1] = 6; matrice[1][2] = 7; matrice[1][3] = 8; matrice[2][0] = 9; matrice[2][1] = 10; matrice[2][2] = 11; matrice[2][3] = 12; |
Dar, am văzut că pentru un șir avem la dispoziție o prescurtare. Am putea rescrie codul astfel:
1 2 3 4 |
int[][] matrice = new int[3][]; matrice[0] = new int[] {1, 2, 3, 4}; matrice[1] = new int[] {5, 6, 7, 8}; matrice[2] = new int[] {9, 10, 11, 12}; |
De fapt, matricea e tot un șir (format din șiruri). Oare nu se poate mai simplu? Ce-ați zice de varianta următoare?
1 |
int[][] matrice = { new int[] {1, 2, 3, 4}, new int[] {5, 6, 7, 8}, new int[] {9, 10, 11, 12} }; |
Am definit un șir format din trei elemente. Primul element este șirul {1, 2, 3, 4}, al doilea este șirul {5, 6, 7, 8}, iar al treilea este șirul {9, 10, 11, 12}.
Ni se oferă mai multe alte construcții care realizează aceeași operație, dar acestea sunt specifice limbajului C# și nu vom insista acum asupra lor.
Parcurgerea matricelor
Putem parcurge matricele aproape la fel cum parcurgem șirurile. Le traversăm linie cu linie și apoi, dacă dorim, putem traversa fiecare linie. Este suficient să avem două bucle imbricate. Următoarea secvență afișează elementele, câte unul pe o linie. Nu va arăta ca o matrice, dar acest aspect nu este important.
1 2 3 4 5 6 7 |
for (int i = 0; i < matrice.Length; i++) { for (int j = 0; j < matrice[i].Length; j++) { System.Console.WriteLine(matrice[i][j]); } } |
Putem încerca și folosind varianta for each:
1 2 3 4 5 6 7 |
foreach (int[] linie in matrice) { foreach (int valoare in linie) { System.Console.WriteLine(valoare); } } |
O simplificare pentru matrice
De cele mai multe ori șirurile de șiruri sunt matrice. Deși există situații în care șirurile individuale ar putea avea dimensiuni diferite, acestea sunt cazuri izolate. De obicei, șirurile au același număr de elemente și avem de-a face cu o matrice.
Când definim o matrice spunem că ea are m linii și n coloane; noi am precizat că matricea are m linii și apoi, pentru fiecare linie în parte, am spus că aceasta are n coloane. Dacă dorim să creăm matrice, limbajul C# ne oferă o construcție mai simplă; putem preciza direct numărul liniilor și al coloanelor. De exemplu, pentru a crea o matrice cu trei linii și patru coloane putem scrie direct:
1 |
int[,] matrice = new int[3,4]; |
A fost creată matricea (echivalent cu int[][] matrice = new int[3][];) și au fost create liniile individuale (echivalent cu matrice[0] = new int[4]; matrice[1] = new int[4]; matrice[2] = new int[4];).
Dar, dacă definim matricea în acest fel, elementele nu vor mai fi accesate folosind construcții de tipul matrice[i][j], ci de tipul matrice[i,j].
Observăm că prima dată este precizat numărul liniilor și apoi cel al coloanelor. De aceea și atunci când construim un șir de șiruri precizând numărul șirurilor scriem acel număr între prima pereche de paranteze, nu între cea de-a doua (a se vedea exemplul de la începutul acestui episod).
Tabla înmulțirii
În episodul X am văzut cum putem afișa tabla înmulțirii. Dar, este mai natural ca o astfel de tablă să fie păstrată într-o matrice. Am putea crea destul de simplu o astfel de matrice astfel:
1 2 3 4 5 6 |
int[,] tablaInmultirii = new int[10,10]; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { tablaInmultirii[i,j] = (i + 1) * (j + 1); } } |
Avem (i + 1) * (j + 1)și nu i * j deoarece în șiruri (deci și în matrice) numerotarea începe de la 0, nu de la 1, iar în tabla înmulțirii avem nevoie de numerele de la 1 la 10, nu de la 0 la 9.
Putem scrie acum și o versiune mai simplă a afișării tablei:
1 2 3 4 5 6 |
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { System.Console.Write("\t" + tablaInmultirii[i,j]); } System.Console.WriteLine(); } |
Va urma
Șirurile sunt foarte utile, dar utilizarea lor incorectă poate duce la greșeli relativ greu de detectat. În următorul episod vom prezenta câteva "capcane" care ar trebui evitate.