Z tablicami mieliśmy już kontakt, być może nieświadomie, przy okazji pętli foreach
, która przechodziła przez znaki obiektu typu string
, będącego tablicą znaków. W tym wpisie omówione zostaną tablice, które są reprezentacją najprostszej kolekcji. Są to obiekty zawierające elementy pewnego typu. Każdy taki element przypomina zmienną, do której możemy się dostać, podając jej numer.
W poniższym przykładzie deklarujemy dwie zmienne tablicowe namesDay
oraz namesMonth
. Rozmiar tablicy określony wraz z jej deklaracją jest niezmienny przez cały okres istnienia tablicy. Rozmiar pierwszej tablicy wyznacza wartość zmiennej countDay
. Należy pamiętać, że rozmiar tablicy nie może być ujemny. Próba ustawienia wartości ujemnej zakończy się błędem ""Cannot create an array with a negative size"". W kolejnych liniach ustawiamy wartości poszczególnych elementów tablicy. Co się stanie, jeżeli spróbujemy odwołać się do elementu spoza tablicy? Na poziomie kompilacji nic. Dopiero w trakcie działania aplikacji zgłosi wyjątek System.IndexOutOfRangeException. Po ustawieniu wartości dla wszystkich elementów pobieramy numer dzisiejszego dnia. Konieczne będzie przekształcenie zwracanego przez DayOfWeek
, będącego typem wyliczeniowym, na liczbową reprezentację. Kończymy wyświetleniem nazwy dzisiejszego dnia. Tablica namesMonth
została zadeklarowana w inny sposób. Nazwę zmiennej tablicy poprzedza słowo var
, a nie jak wcześniej nazwa typu tablicy. Jeżeli znasz działanie var
z innych języków, np. JavaScript, to w przypadku C# działa on inaczej. Przede wszystkim C# jest silnie typowany, nie możemy do zmiennej typu int
wstawić zmiennej typu decimal
. Tak naprawdę var
jest zamiennikiem dla typu zmiennej i podczas kompilacji CLR w to miejsce wstawia odpowiedni typ. Osobiście staram się nie duplikować nazw typów. W sytuacji, gdy typ zmiennej nie wynika wprost z kodu, zostawiam odpowiedni typ zmiennej. Kolejna różnica dotyczy deklarowanego rozmiaru tablicy. Rozmiar pierwszej tablicy został określony przez wartość zmiennej countDay
. W przypadku drugiej tablicy nie określamy rozmiaru, lecz wewnątrz { ... }
definiujemy wszystkie wartości. Na koniec wyświetlamy nazwę bieżącego miesiąca.
using System;
namespace HelloWorld
{
public static class Program
{
public static void Main()
{
int countDay = 7;
string[] namesDay = new string[countDay];
namesDay[0] = "Sunday";
namesDay[1] = "Monday";
namesDay[2] = "Tuesday";
namesDay[3] = "Wednesday";
namesDay[4] = "Thursday";
namesDay[5] = "Friday";
namesDay[6] = "Saturday";
int today = (int)DateTime.Now.DayOfWeek;
Console.WriteLine("Present day: " + namesDay[today]);
var namesMonth = new string[] { "January", "February", "March", "April",
"May", "June", "July", "August", "September", ""October"",
"November", "December" };
Console.WriteLine("Current month: " + namesMonth[DateTime.Now.Month - 1]);
Console.ReadLine();
}
}
}
W przypadku tablic istnieje możliwość pominięcia słowa kluczowego new
, wymaga to jawnego określenia typu wraz z początkową inicjalizacją wartości.
int[] numbers = { 1, 3, 4, 7 };
Wiemy już, jak tworzyć oraz używać tablic. Teraz zajmijmy się wyszukaniem elementu. Najprostszym rozwiązaniem będzie użycie pętli do iteracji elementów i porównywania wartości elementu z szukaną wartością.
using System;
namespace HelloWorld
{
public static class Program
{
public static void Main()
{
int countDay = 7;
var namesDay = new string[countDay];
for (int idx = 0; idx < countDay; idx++)
namesDay[idx] = ((DayOfWeek)idx).ToString();
for (int idx = 0; idx < countDay; idx++)
{
if (namesDay[idx] == "Friday")
{
Console.WriteLine("Loop for - Find index for friday: " + idx);
break;
}
}
Console.ReadLine();
}
}
}
Przykład rozpoczynamy od deklaracji tablicy namesDay
, której rozmiar określa zmienna countDay
. Następnie korzystamy z publicznego typu wyliczeniowego DayOfWeek
, który reprezentuje dni tygodnia, w celu napełnienia tablicy danymi. Na chwilę obecną nie skupiajmy się na sposobie zasilenia tablicy, w kolejnych notatkach postaram się opisać temat konwersji danych. Przejdźmy do sedna, czyli wyszukania tekstu "Friday". W pętli for przechodzimy przez wszystkie elementy, sprawdzając w każdej iteracji czy wartość elementu jest szukanym ciągiem znaków. Po dopasowaniu wartości wyświetlamy numer indeksu. Kończymy instrukcją break
. Za co odpowiada instrukcja? Ma ona za zadanie przerwać działanie pętli po wyszukaniu pierwszego pasującego elementu. W sytuacji, gdy pozbędziemy się instrukcji przerwania, a w samej tablicy wartość "Friday" występowałaby kilkukrotnie, wyświetlany tekst również pojawiłby się kilkukrotnie.
Alternatywą dla tworzenia własnego kodu do przeszukiwania tablic jest użycie wbudowanych mechanizmów. Zestaw narzędzi wspomagających operacje na tablicach znajduje się w klasie Array
. W przykładzie poniżej korzystam z metody IndexOf
, która w parametrach przyjmuje tablicę oraz szukaną wartość. Zwraca natomiast indeks pierwszego elementu spełniającego warunek.
using System;
namespace HelloWorld
{
public static class Program
{
public static void Main()
{
int countDay = 7;
var namesDay = new string[countDay];
for (int idx = 0; idx < countDay; idx++)
namesDay[idx] = ((DayOfWeek)idx).ToString();
int fridayIdx = Array.IndexOf(namesDay, "Friday");
Console.WriteLine("Array.IndexOf - Find index for friday: " + fridayIdx);
Console.ReadLine();
}
}
}
Przekształćmy wcześniejszy przykład tak, aby wyświetlił wszystkie dni tygodnia rozpoczynające się od "T". W tym celu zamiast porównania wykonamy sprawdzenie, czy ciąg rozpoczyna się od szukanego znaku. Możemy "ręcznie" zweryfikować pierwszy znak element namesDay[idx][0] == "T"
lub użyć metody StartsWith
, która działa identycznie. Dodatkowo użyjemy metody FindAll
, która nie zwraca indeksu, a element (dokładniej wszystkie elementy spełniające warunek). W parametrach przekazujemy tablicę oraz metodę weryfikującą wartość elementu. Dostępna jest również metoda Find
, która zwraca pierwszy element.
using System;
namespace HelloWorld
{
public static class Program
{
public static void Main()
{
int countDay = 7;
var namesDay = new string[countDay];
for (int idx = 0; idx < countDay; idx++)
namesDay[idx] = ((DayOfWeek)idx).ToString();
for (int idx = 0; idx < countDay; idx++)
if (namesDay[idx].StartsWith("T"))
Console.WriteLine(namesDay[idx]);
Console.WriteLine("---------------");
string[] findDays = Array.FindAll(namesDay, CheckCondition);
foreach(var day in findDays)
Console.WriteLine(day);
Console.ReadLine();
}
private static bool CheckCondition(string value)
{
return value.StartsWith("T");
}
}
}
Klasa Array
oprócz już wymienionych metod udostępnia zestaw dodatkowych rozwiązań umożliwiających np. kopiowanie elementów pomiędzy tablicami metodą Copy
, czy zmianę rozmiaru tablicy metodą Resize
. Należy jednak pamiętać, że zgodnie z tym, co napisałem na początku, zadeklarowany rozmiar tablicy obowiązuje do momentu zwolnienia pamięci. Wspomniana metoda Resize
nie zmienia rozmiaru, a tworzy nową tablicę o podanym rozmiarze, kopiując elementy. W przypadku zmniejszania rozmiaru, elementy, dla których brakuje miejsca, zostaną utracone.
W następnych notatkach dotyczących przeszukiwania tablic oraz tablic wielowymiarowych znajdziemy kolejną porcję wiedzy.
Troska Robert