16. Kolekcje

16. Kolekcje

 Daniel Celeda
Daniel Celeda
00:00
23.05.2006
179278 wyświetleń

Wiemy już do czego służą tablice. Czas poznać ich bliskich znajomych – kolekcje. Przestrzenią nazw, której będziemy musieli użyć jest „System.Collections”. Najbardziej znaną i najczęściej stosowaną kolekcją jest „ArrayList”. Jest to lista, w której tak jak w tablicy możemy przechowywać wiele elementów, jednak jest łatwiejsza w obsłudze.

Czemu więc używać zwykłych tablic?

Mają one kilka zalet, których nie posiada „ArrayList”.
Po pierwsze, podczas deklarowania tablicy określamy jakiego typu będą elementy w niej przechowywane. Dzięki tej deklaracji unikamy błędów już na etapie kompilacji polegających na dodawaniu do tablicy elementu o innym typie niż się spodziewaliśmy (kompilator wygeneruje błąd). Dodatkowo tablice działają szybciej niż „ArrayList”.

Kiedy więc używać kolekcji?

Kolekcje dają nam większa swobodę kosztem wydajności. Nie musimy ustalać rozmiaru listy tak jak to się robi w tablicach. Po prostu dodajemy bądź usuwamy kolejne elementy. „ArrayList” posiada wiele metod, które upraszczają jej obsługę oraz udostępniają dodatkową funkcjonalność. W poprzednim ćwiczeniu tworzyliśmy tablicę wypełnioną liczbami a następnie sortowaliśmy je. Używając „ArrayListy” sortować możemy za pomocą metody „Sort()”. Elementy dodajemy do kolekcji wykonując metodę „Add()”. W tym momencie kolekcja dodaje referencję do tego elementu traktując go jak obiekt klasy „object”.

using System;
using System.Collections;
 
namespace Kolekcje
{
class Program
{
static void Main(string[] args)
{
ArrayList lista = new ArrayList();
lista.Add(2);
lista.Add(11);
lista.Add(-2);
lista.Add(4);
 
Console.Write("Elementy nieposortowane: ");
for (int i = 0; i < 4; i++)
{
Console.Write(lista[i] + " ");
}
 
lista.Sort();
Console.Write("\nElementy posortowane: ");
for (int i = 0; i < 4; i++)
{
Console.Write(lista[i] + " ");
}
 
 
Console.ReadKey();
}
}

Wynik:

W następnym programie spróbujemy na liście umieścić elementy będące instancjami klasy, którą sami stworzymy.
Najpierw napiszmy program, w którym umieścimy dwa obiekty naszej klasy pomocniczej na liście, a następnie spróbujemy pobrać te elementy i bez rzutowania dostać się do zmiennej „Liczba”.

using System;
using System.Collections;
 
namespace Kolekcje
{
class Element
{
public int Liczba;
 
public Element(int liczba)
{
this.Liczba = liczba;
}
}
 
class Program
{
static void Main(string[] args)
{
Element element_1 = new Element(10);
Element element_2 = new Element(20);
 
ArrayList lista = new ArrayList();
 
lista.Add(element_1);
lista.Add(element_2);
 
int nowaZmienna = lista[0].Liczba;
 
Console.ReadKey();
}
}
}

Powyższy program nie skompiluje się, ponieważ po pobraniu elementu z listy nie zrzutowaliśmy go na typ „KlasaPomocnicza”. Element więc jest traktowany jako instancja klasy „object”, która nie posiada zmiennej „Liczba”.

Error 1 'object' does not contain a definition for 'Liczba'

Poniżej poprawnie działający program, wykonujący rzutowanie.

using System;
using System.Collections;
 
namespace Kolekcje
{
class Element
{
public int Liczba;
 
public Element(int liczba)
{
this.Liczba = liczba;
}
}
 
class Program
{
static void Main(string[] args)
{
Element element_1 = new Element(10);
Element element_2 = new Element(20);
 
ArrayList lista = new ArrayList();
 
lista.Add(element_1);
lista.Add(element_2);
 
int nowaZmienna = ((Element)lista[0]).Liczba;
 
Console.ReadKey();
}
}
}

@STRONA@

Kod ((Element)lista[0]).Liczba najpierw wykonuje rzutowanie elementu o indeksie „0” na typ „Element”, a następnie pobierana jest wartość zmiennej „Liczba”. Nawiasy określają kolejność wykonania operacji. W przypadku ich braku (Element)lista[0].Liczba kompilator chce rzutować nie element „lista[0]” lecz zmienną „Liczba”, a ponieważ w tym momencie element jest traktowany jako obiekt klasy „object”, wygenerowany zostanie błąd ponieważ klasa „object” nie posiada zmiennej „Liczba”.

Napiszmy teraz program, w którym przechowywać na liście oraz w tablic będziemy obiekty klasy „Element”.

using System;
using System.Collections;
 
namespace Kolekcje
{
class Element
{
public int Liczba;
 
public Element(int liczba)
{
this.Liczba = liczba;
}
}
 
class Program
{
static void Main(string[] args)
{
Element[] tablica = new Element[2];
tablica[0] = new Element(10);
tablica[1] = new Element(20);
 
ArrayList lista = new ArrayList(tablica);
 
Console.Write("Elementy na liście: ");
for (int i = 0; i < lista.Count; i++)
{
int liczba = ((Element)lista[i]).Liczba;
Console.Write(liczba + " ");
}
 
Element nowyElement = new Element(123);
lista.Insert(1, nowyElement);
Console.Write("\nElementy na liście: ");
for (int i = 0; i < lista.Count; i++)
{
int liczba = ((Element)lista[i]).Liczba;
Console.Write(liczba + " ");
}
 
lista.RemoveAt(0);
Console.Write("\nElementy na liście: ");
for (int i = 0; i < lista.Count; i++)
{
int liczba = ((Element)lista[i]).Liczba;
Console.Write(liczba + " ");
}
 
Console.ReadKey();
}
}
}

Najpierw zdefiniowaliśmy sobie naszą klasę. Następnie stworzyliśmy tablicę dwuelementową i dodaliśmy do niej dwa obiekty. Posiadając wypełnioną tablicę, przekazaliśmy ją jako parametr do konstruktora „ArrayListy” i stworzyliśmy nową kolekcję na podstawie elementów znajdujących się w tablicy.
Metoda „Insert()” umieszcza element w kolekcji. Jako parametry podajemy indeks, który określa nam miejsce w kolekcji, w które chcemy wstawić element oraz drugi parametr to wstawiany obiekt.
Zmienna „Count” określa ile elementów zawiera lista, więc dzięki niej możemy użyć pętli „for” w celu wypisania wszystkich elementów.
Jeśli chcemy usunąć jakiś element znając jego indeks (miejsce które zajmuje w kolekcji) możemy użyć metody „RemoveAt()”. Jako parametr podajemy liczbę całkowitą będącą indeksem.

ArrayList” posiada znacznie więcej metod niż przedstawione w tym artykule. Są one dobrze opisane w MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemcollectionsarraylistclasstopic.asp), tak więc zachęcam do zapoznania się z nimi. Przestrzeń nazw „System.Collections” zawiera jeszcze kilka rodzajów kolekcji, jednak ograniczone ramy tego kursu nie pozwalają na ich przedstawienie. Jedną z ciekawszych jest „Hashtable”, której działanie, przy większej ilości elementów, jest znacznie szybsze niż „ArrayListy”.

Pętla „foreach”.

Poznaliśmy już tablice oraz kolekcję, więc jesteśmy już w stanie zrozumieć działanie pętli „foreach”. Nie omawiałem jej w temacie poświęconym instrukcjom iteracyjnym, ponieważ jej działanie opiera się na iterowaniu po elementach znajdujących się w jakimś elemencie złożonym (np. tablicy). Dla uproszczenia będę mówił o kolekcjach. Jej składnia wygląda następująco:

foreach(typ tymczasowyElement in kolekcja)
{
//ciało pętli
}

Zacznijmy od tego, że po słówku „in” w miejsce słowa „kolekcja” należy wstawić kolekcję po której chcemy iterować (dostać się do elementów znajdujących się w danej kolekcji). Zamiast „typ” piszemy nazwę klasy, której to instancje znajdują się w kolekcji. Natomiast „tymczasowyElement” to element, który pobieramy na czas trwania jednej iteracji. Ponieważ w kolekcjach elementy przechowywane są jako instancje klasy „object”, nie moglibyśmy używać składowych (metod, zmiennych itd.) obiektów, które znajdują się w kolekcji. Podanie typu (w miejscu „typ”) powoduje, że każdy element w poszczególnej iteracji jest rzutowany na ten typ.
Przykład:

using System;
using System.Collections;
 
namespace Kolekcje
{
class Element
{
public int Liczba;
 
public Element(int liczba)
{
this.Liczba = liczba;
}
}
 
class Program
{
static void Main(string[] args)
{
Element element_1 = new Element(10);
Element element_2 = new Element(20);
Element element_3 = new Element(30);
 
ArrayList lista = new ArrayList();
 
lista.Add(element_1);
lista.Add(element_2);
lista.Add(element_3);
 
Console.Write("Elementy: ");
foreach (Element element in lista)
{
Console.Write(element.Liczba + " ");
}
 
Console.ReadKey();
}
}

Wynik (Ctrl + F5):

Ćwiczenie.

Napisać program pobierający pięć liczb od użytkownika i dodający je do „ArrayListy”. Następnie program usunie element o indeksie 2 oraz posortuje liczby. Należy wyszukać metodę, która zamienia kolejność elementów na odwrotną i wykonać ją na liście. Za pomocą pętli „foreach” należy wypisać wyniki po każdej ze zmian.

using System;
using System.Collections;
 
namespace Kolekcje
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayList lista = new ArrayList();
 
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Podaj liczbę.");
                int liczba =  int.Parse(Console.ReadLine());
                lista.Add(liczba);
            }
 
            Console.Write("\nElementy: ");
            foreach (int liczba in lista)
            {
                Console.Write(liczba + " ");
            }
 
            lista.RemoveAt(2);
 
            Console.Write("\nElementy: ");
            foreach (int liczba in lista)
            {
                Console.Write(liczba + " ");
            }
 
            lista.Sort();
            Console.Write("\nElementy: ");
            foreach (int liczba in lista)
            {
                Console.Write(liczba + " ");
            }
 
            lista.Reverse();
            Console.Write("\nElementy: ");
            foreach (int liczba in lista)
            {
                Console.Write(liczba + " ");
            }
 
            Console.ReadKey();
        }
    }
}


Spodobał Ci się ten artykuł? Podziel się z innymi!

Źródło:

Polecamy również w kategorii Kurs C#, cz. I