Słowniki (Dictionary)

Słowniki (dictionary) to struktura danych zawierająca zbiór par klucz-wartość, inaczej mówiąc to kolekcja, która zawiera wartości powiązane z kluczami. W tablicach, do wartości w niej zapisanych, odwołujemy się za pomocą indeksu czyli położenia tej wartości wewnątrz tablicy. W słownikach do określonego klucza przypisana jest konkretna wartość czyli chcąc pobrać wartość ze słownika musimy odwołać się do niej przez klucz. Klucze i wartości mogą być obiektami dowolnego typu. Ponadto klucze muszą być unikatowe i różne od null.

Użycie słowników zilustrujmy następującym przykładem. Załóżmy że chcemy uzyskać następującą strukturę danych: dla każdego z szesnastu województw Polski chcemy zapisać jego stolicę. Województwa wraz ze stolicami (w kolejności alfabetycznej):

|Nr| Nazwa województwa        | Stolica                    |
|--|--------------------------|----------------------------|
| 1| Dolnośląskie             | Wrocław                    |
| 2| Kujawsko-Pomorskie       | Bydgoszcz                  |
| 3| Lubelskie                | Lublin                     |
| 4| Lubuskie                 | Gorzów Wielkopolski        |
| 5| Łódzkie                  | Łódź                       |
| 6| Małopolskie              | Kraków                     |
| 7| Mazowieckie              | Warszawa                   |
| 8| Opolskie                 | Opole                      |
| 9| Podkarpackie             | Rzeszów                    |
|10| Podlaskie                | Białystok                  |
|11| Pomorskie                | Gdańsk                     |
|12| Śląskie                  | Katowice                   |
|13| Świętokrzyskie           | Kielce                     |
|14| Warmińsko-Mazurskie      | Olsztyn                    |
|15| Wielkopolskie            | Poznań                     |
|16| Zachodniopomorskie       | Szczecin                   |

Można oczywiście powyższe stolice województw wprowadzić do tablicy, wówczas uzyskamy szesnasto elementową tablicę ale jej użycie będzie bardzo uciążliwe. Gdybyśmy chcieli pobrać stolicę np. województwa podkarpackiego to musimy pamiętać że w kolejności alfabetycznej znajduje się ono na dziewiątej pozycji (w tablicy na ósmej - elementy tablic liczone są od zera). Zamiast tego łatwiej jest użyć słowników czyli kolekcji danych przechowujących pary klucz-wartość.
Słowniki zdefiniowane są w następującej przestrzeni nazw/module:

uses Generics.Collections;
using System.Collections.Generic;

Zadeklarujmy zatem obiekt typu słownikowego i wprowadźmy do niego nasze dane:

procedure DictionaryTest();
var
  //deklaracja słownika
  stoliceWojewodztw : TDictionary<string, string>;
begin
  //inicjalizacja słownika
  stoliceWojewodztw := TDictionary<string, string>.Create();

  //wprowadzanie danych
  stoliceWojewodztw.Add('Dolnośląskie', 'Wrocław');
  stoliceWojewodztw.Add('Kujawsko-Pomorskie', 'Bydgoszcz');
  stoliceWojewodztw.Add('Lubelskie', 'Lublin');
  stoliceWojewodztw.Add('Lubuskie', 'Gorzów Wielkopolski');
  stoliceWojewodztw.Add('Łódzkie', 'Łódź');
  stoliceWojewodztw.Add('Małopolskie', 'Kraków');
  stoliceWojewodztw.Add('Mazowieckie', 'Warszawa');
  stoliceWojewodztw.Add('Opolskie', 'Opole');
  stoliceWojewodztw.Add('Podkarpackie', 'Rzeszów');
  stoliceWojewodztw.Add('Podlaskie', 'Białystok');
  stoliceWojewodztw.Add('Pomorskie', 'Gdańsk');
  stoliceWojewodztw.Add('Śląskie', 'Katowice');
  stoliceWojewodztw.Add('Świętokrzyskie', 'Kielce');
  stoliceWojewodztw.Add('Warmińsko-Mazurskie', 'Olsztyn');
  stoliceWojewodztw.Add('Wielkopolskie', 'Poznań');
  stoliceWojewodztw.Add('Zachodniopomorskie', 'Szczecin');
end;
private void DictionaryTest()
{
    //deklaracja i inicjalizacja słownika
    Dictionary<string, string> stoliceWojewodztw = new Dictionary<string, string>();

    //wprowadzanie danych
    stoliceWojewodztw.Add("Dolnośląskie", "Wrocław");
    stoliceWojewodztw.Add("Kujawsko-Pomorskie", "Bydgoszcz");
    stoliceWojewodztw.Add("Lubelskie", "Lublin");
    stoliceWojewodztw.Add("Lubuskie", "Gorzów Wielkopolski");
    stoliceWojewodztw.Add("Łódzkie", "Łódź");
    stoliceWojewodztw.Add("Małopolskie", "Kraków");
    stoliceWojewodztw.Add("Mazowieckie", "Warszawa");
    stoliceWojewodztw.Add("Opolskie", "Opole");
    stoliceWojewodztw.Add("Podkarpackie", "Rzeszów");
    stoliceWojewodztw.Add("Podlaskie", "Białystok");
    stoliceWojewodztw.Add("Pomorskie", "Gdańsk");
    stoliceWojewodztw.Add("Śląskie", "Katowice");
    stoliceWojewodztw.Add("Świętokrzyskie", "Kielce");
    stoliceWojewodztw.Add("Warmińsko-Mazurskie", "Olsztyn");
    stoliceWojewodztw.Add("Wielkopolskie", "Poznań");
    stoliceWojewodztw.Add("Zachodniopomorskie", "Szczecin");
}

Pary klucz-wartość zostały dodane do słowników. Jak teraz pobrać stolicę województwa podkarpackiego? Posłużmy się przykładem:

Writeln(stoliceWojewodztw['Podkarpackie']);
Console.WriteLine(stoliceWojewodztw["Podkarpackie"]);

Na konsolę zostanie wypisane: Rzeszów. Jak widać użycie słowników jest w tym przypadku znacznie łatwiejsze i przyjemniejsze niż tablic. Nie musimy pamiętać na której pozycji znajduje się interesujący nas element.

Wspomniałem już wcześniej że klucze w słowniku muszą być unikatowe, nie mogą się powtarzać. Załóżmy, że do słownika chcemy wprowadzić pary wartości Imię i Nazwisko pracowników jakiejś firmy:

procedure DictionaryTest();
var
  //deklaracja słownika
  pracownicy : TDictionary<string, string>;
begin
  //inicjalizacja słownika
  pracownicy := TDictionary<string, string>.Create();

  //wprowadzanie danych
  pracownicy.Add('Jan', 'Nowak');
  pracownicy.Add('Jan', 'Kowalski');
end;
private void DictionaryTest()
{
    //deklaracja i inicjalizacja słownika
    Dictionary<string, string> pracownicy = new Dictionary<string, string>();

    //wprowadzanie danych
    pracownicy.Add("Jan", "Nowak");
    pracownicy.Add("Jan", "Kowalski");
}

Taka deklaracja słownika spowoduje błąd działania programu. Błąd ten nie będzie zgłaszany przez kompilator, składniowo wszystko jest poprawne. Jednak po wywołaniu metody DictionaryTest otrzymamy:

EListError: Duplicates not allowed
System.ArgumentException: Element o tym samym kluczu został już dodany

Należy na to uważać podczas projektowania aplikacji. Można zabezpieczyć się przed tym błędem sprawdzając, przed dodaniem pary do słownika, czy element o danym kluczu nie znajduje się już w słowniku np.

//sprawdzenie czy w słowniku nie znajduje się już taki element
if (pracownicy.ContainsKey('Jan')) then
  Writeln('Element o takim kluczu znajduje się już w słowniku')
 else
  pracownicy.Add('Jan', 'Kowalski');
//sprawdzenie czy w słowniku nie znajduje się już taki element
if (pracownicy.ContainsKey("Jan"))
    Console.WriteLine("Element o takim kluczu znajduje się już w słowniku");
else
    pracownicy.Add("Jan", "Kowalski");

Dodatkowo Delphi udostępnia procedurę AddOrSetValue która przed dodaniem pary klucz-wartość do słownika sprawdza czy element o takim kluczu nie znajduje się w słowniku. Jeżeli jest już dodany to elementowi temu zostanie zmieniona wartość na aktualnie dodawaną.

procedure DictionaryTest();
var
  //deklaracja słownika
  pracownicy : TDictionary<string, string>;
  kvp : TPair<string, string>;
begin
  //inicjalizacja słownika
  pracownicy := TDictionary<string, string>.Create();

  //wprowadzanie danych
  pracownicy.AddOrSetValue('Jan', 'Nowak');
  pracownicy.AddOrSetValue('Jan', 'Kowalski');
end;

Takie wywołanie procedury DictionaryTest spowoduje że w słowniku pracownicy znajduje się TYLKO JEDEN element zawierający następujące dane: klucz: Jan, wartość: Kowalski.

Pobranie pary klucz-wartość, iterowanie elementów słownika

Słownik to kolekcja danych, kolekcja par, klucz-wartość. Pary są określonego typu:

TPair<TKey,TValue>
KeyValuePair<TKey, TValue>

Zatem aby pobrać taką parę czyli pojedynczy element słownika można to zrobić w następujący sposób:

procedure DictionaryTest();
var
  //deklaracja słownika
  stoliceWojewodztw : TDictionary<string, string>;

  //deklaracja pary klucz-wartosc
  para : TPair<string, string>;
begin
  //inicjalizacja słownika
  stoliceWojewodztw := TDictionary<string, string>.Create();

  //wprowadzanie danych
  stoliceWojewodztw.Add('Dolnośląskie', 'Wrocław');
  stoliceWojewodztw.Add('Kujawsko-Pomorskie', 'Bydgoszcz');
  stoliceWojewodztw.Add('Lubelskie', 'Lublin');
  stoliceWojewodztw.Add('Lubuskie', 'Gorzów Wielkopolski');
  stoliceWojewodztw.Add('Łódzkie', 'Łódź');
  stoliceWojewodztw.Add('Małopolskie', 'Kraków');
  stoliceWojewodztw.Add('Mazowieckie', 'Warszawa');
  stoliceWojewodztw.Add('Opolskie', 'Opole');
  stoliceWojewodztw.Add('Podkarpackie', 'Rzeszów');
  stoliceWojewodztw.Add('Podlaskie', 'Białystok');
  stoliceWojewodztw.Add('Pomorskie', 'Gdańsk');
  stoliceWojewodztw.Add('Śląskie', 'Katowice');
  stoliceWojewodztw.Add('Świętokrzyskie', 'Kielce');
  stoliceWojewodztw.Add('Warmińsko-Mazurskie', 'Olsztyn');
  stoliceWojewodztw.Add('Wielkopolskie', 'Poznań');
  stoliceWojewodztw.Add('Zachodniopomorskie', 'Szczecin');

  //iterowanie elementow slownika
  for para in stoliceWojewodztw do
    Writeln(Format('Województwo: %s   Stolica: %s', [para.Key, para.Value]));
end;
private void DictionaryTest()
{
    //deklaracja i inicjalizacja słownika
    Dictionary<string, string> stoliceWojewodztw = new Dictionary<string, string>();

    //wprowadzanie danych
    stoliceWojewodztw.Add("Dolnośląskie", "Wrocław");
    stoliceWojewodztw.Add("Kujawsko-Pomorskie", "Bydgoszcz");
    stoliceWojewodztw.Add("Lubelskie", "Lublin");
    stoliceWojewodztw.Add("Lubuskie", "Gorzów Wielkopolski");
    stoliceWojewodztw.Add("Łódzkie", "Łódź");
    stoliceWojewodztw.Add("Małopolskie", "Kraków");
    stoliceWojewodztw.Add("Mazowieckie", "Warszawa");
    stoliceWojewodztw.Add("Opolskie", "Opole");
    stoliceWojewodztw.Add("Podkarpackie", "Rzeszów");
    stoliceWojewodztw.Add("Podlaskie", "Białystok");
    stoliceWojewodztw.Add("Pomorskie", "Gdańsk");
    stoliceWojewodztw.Add("Śląskie", "Katowice");
    stoliceWojewodztw.Add("Świętokrzyskie", "Kielce");
    stoliceWojewodztw.Add("Warmińsko-Mazurskie", "Olsztyn");
    stoliceWojewodztw.Add("Wielkopolskie", "Poznań");
    stoliceWojewodztw.Add("Zachodniopomorskie", "Szczecin");

    //iterowanie elementow slownika
    foreach (KeyValuePair<string, string> para in stoliceWojewodztw)
    {
        Console.WriteLine(String.Format("Województwo: {0}   Stolica: {1}", para.Key, para.Value));
    }
}

Iterowanie po kluczach lub wartościach

Aby iterować elementy słownika nie koniecznie trzeba iterować po parach wartości klucz-wartość. Można iterować po samych kluczach lub samych wartościach

//iterowanie po kluczach
for s in stoliceWojewodztw.Keys do
  Writeln(Format('Klucz ze słownika: %s', [s]));

//iterowanie po wartościach
for s in stoliceWojewodztw.Values do
  Writeln(Format('Wartość ze słownika: %s', [s]));
//iterowanie po kluczach
foreach (string s in stoliceWojewodztw.Keys)
{
    Console.WriteLine(String.Format("Klucz ze słownika: {0}", s));
}
            
//iterowanie po wartościach
foreach (string s in stoliceWojewodztw.Values)
{
    Console.WriteLine(String.Format("Wartość ze słownika: {0}", s));
}

Zwalnianie pamięci po zmiennych typu Dictionary

procedure DictionaryTest();
//deklaracja słownika
var stoliceWojewodztw : TDictionary<string, string>;
begin
//inicjalizacja słownika
stoliceWojewodztw := TDictionary<string, string>.Create();

try
   //jakieś operacje na słowniku
finally
   //zwalnianie pamięci zajmowanej przez słownik
   if (Assigned(stoliceWojewodztw)) then stoliceWojewodztw.Free;
end;
end;
private void DictionaryTest()
{
  //deklaracja i inicjalizacja słownika
  Dictionary<string, string> stoliceWojewodztw = new Dictionary<string, string>();

  try
  {
      //jakieś operacje na słowniku
  }
  finally
  {
      //jakieś operacje na słowniku
      if (stoliceWojewodztw != null)
      {
          stoliceWojewodztw.Clear();
          stoliceWojewodztw.Distinct();
      }
  }
}

 

Dodaj nowy komentarz

Filtrowany HTML

  • Adresy internetowe są automatycznie zamieniane w odnośniki, które można kliknąć.
  • Dozwolone znaczniki HTML: <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Znaki końca linii i akapitu dodawane są automatycznie.
  • Tekstowe buźki będą zamieniane na ich graficzne odpowiedniki.

Czysty tekst

  • Znaczniki HTML niedozwolone.
  • Adresy internetowe są automatycznie zamieniane w odnośniki, które można kliknąć.
  • Znaki końca linii i akapitu dodawane są automatycznie.
  • Tekstowe buźki będą zamieniane na ich graficzne odpowiedniki.
CAPTCHA
W celu potwierdzenia, że jesteś człowiekiem, prosimy o wykonanie poniższego zadania
Target Image