Hashtable in C#

Hashtables (Hash-Tabellen) sind Datenstrukturen, die den Arrays sehr ähnlich sind.
Hashtables können in C# ähnlich wie eine ArrayList verwendet werden, der Zugriff erfolgt über einen Index.
Der Index ist ein spezieller Key, welcher eine Zahl (z.B. vom Typ Float oder Integer) genauso wie ein String sein darf.

[csharp] // Beispiele, Syntax: hashtablename[key] = value;

ht_pass[32.3] = “juhu”;
ht_pass[5] = “tobias”;
ht_pass[“zoo”] = 45.3;
[/csharp]

Wozu werden Hashtables benötigt?

Hashtables sind sinnvoll, wenn sich Listen bzw. Arrays verknüpfen bzw. verschachteln lassen. So kann der Wert eines Listenfeldes der Schlüssel zu einem Wert eines anderen Feldes sein. Zwar ließe sich das auch mit einem normalen Array
(und somit Integer-Werten als Index) realisieren, dann wären jedoch einige zusätzliche Listen/Tabellen nötig, um von einer
Zahl auf einen speziellen Schlüssel und von diesem Schlüssel wieder auf eine anderen Zahlenschlüssel zu verweisen.

C# bietet natürlich einen gewissen Komfort bei Benutzung von Hashtables (wie bei vielen anderen Dingen auch). In der Programmiersprache C haben Programmierer eigene Hash-Funktionen entwickelt, um z.B. einen Text als Zahl umzuschlüsseln (z.B. “Hallo” -> “2342424”, “Schule” -> “792942” usw.), um diesen dann als Index (Schlüssel) für ein Array zu benuten. Vorteil: Um einen Wert zu suchen, musste nicht unbedingt das ganze Array durchlaufen und im
schlimmsten Falle alle Felder iteriert werden. Man musste sich nur die Schlüssel für bestimmte Werte merken, diese in eine Zahl konvertieren, auf den Wert im Feld mit dem Schlüssel zugreifen und es auslesen. Daraus ergibt sich ein sehr großer Geschwindigkeitsvorteil.
Der Nachteil liegt in der Größe des Arrays, dieses muss nämlich so groß sein bzw. so einen hohen Index haben, wie eine Zahl, die aus einem Text resultiert, werden kann. Außerdem könnte es vorkommen, dass Werte nicht abgespeichert werden können, da zwei oder mehrere unterschiedliche Texte trotz ausgereiften Algorithmus den selben Index ergeben. Ausweichmöglichkeiten sind zwar vorhanden (den Index verschieben, bis ein freies Feld gefunden wurde), macht die Sache jedoch trotzdem nicht viel unproblematischer.

Die Hashtables in C# sind weitaus dynamischer, denn intern ist ein Hahstable auch nur so groß, wie es notwendig ist. Der Zugriff ist jedoch absolut schnell, konstant schnell! Unabhängig von der Größe des Hashtable ist die Zugriffszeit konstant.

Verwendung von Hashtables

Um die Klasse Hashtable verfügbar zu machen, muss der Namespace Collections benutzt werden.

[csharp]

using System.Collections;

[/csharp]

Ein Anwendungsbeispiel:

Es soll ein Hashtable angelegt werden, welcher Benutzernamen als Key mit dazugehörigem Benutzerpasswort als Value speichert.

[csharp]

// Deklaration
Hashtable ht_pass;

// Instanziierung des Hashtable ht_pass

ht_pass = new Hashtable();

// Anlegen von Schlüssel-Werte-Paare, ähnlich einem normalen Array

ht_pass[“benny”] = “porsche”;
ht_pass[“david”] = “programmierer”;
ht_pass[“thomas”] = “kaufmann”;
ht_pass[“daniela”] = “hamburg”;
ht_pass[“sarah”] = “universität”;

[/csharp]

Nun können die Passwörter ausgegeben werden, beispielweise:

[csharp] Console.WriteLine(this.ht_pass[“benny”].ToString());
[/csharp]

Ausgabe:

porsche

Aber Vorsicht! Wird ein Schlüssel in den Hashtable eingesetzt, welcher nicht im Hashtable vorkommt, geschieht eine Exception! (Programmabsturz)

Daher wird eine Methode implementiert, welche vorher prüft, ob der Hashtable nicht Null ist und der gewünschte Key im Hashtable vorkommt und erst dann auf das Value zugreift bzw. es nicht versucht, auf einen Wert zuzugreifen.

[csharp] private string GetHashTableValueByIndey(Hashtable ht, string key)
{
string return_string;

if (ht != null && ht.ContainsKey(key))
{
return_string = ht[key].ToString();
}
else
{
return_string = “[Wert-Schlüssel-Paar mit Schlüssel ‘” + key + “‘ existiert nicht]”;
}

return return_string;
}
[/csharp]

Um den gesamten Inhalt des Hashtable zu illustrieren, wird eine weitere Methode ShowAllItems() implementiert:

[csharp] private void ShowAllItems(Hashtable hashtable)
{
foreach (object key in hashtable.Keys)
{
Console.WriteLine(“Key: ” + key.ToString() + “; Value: ” + hashtable[key].ToString());
}
}
[/csharp]

Wenn diese Methode mit dem Hashtable ht_pass als Parameter aufgerufen wird….
[csharp] this.ShowAllItems(ht_pass);
[/csharp]

… erfolgt die Ausgabe der Schlüssel-Werte-Paare.

Ausgabe:

Key: daniela; Value: hamburg
Key: benny; Value: porsche
Key: sarah; Value: universität
Key: thomas; Value: kaufmann
Key: david; Value: programmierer

Verschachtelung von Hashtables

Ein weiterer Hashtable wird deklariert, welcher eine Beschreibung (Value) zu einem Objekt (Key) bereithält. Die Beschreibung soll einen Hinweis/Tipp auf ein Passwort sein.

[csharp] Hashtable ht_tipp;
[/csharp]

Dazu wird eine neue Methode implementiert, die den Hashtable instanziiert und mit Werten füllt.

[csharp] private void InitializeHashtable2()
{
this.ht_tipp = new Hashtable();

this.ht_tipp.Add(“hamburg”, “stadt”);
this.ht_tipp.Add(“bmw”, “automarke”);
this.ht_tipp.Add(“porsche”, “automarke”);
this.ht_tipp.Add(“universität”, “öffentliche Einrichtung”);
}
[/csharp]

Wie im Beispiel zu erkennen, können Schlüssel-Werte-Paare auch mit der Methode Add() hinzugefügt werden. Der erste Parameter der Methode Add() ist der Schlüssel, der zweite Parameter der Wert.

Diese Methode InitializeHashtable2() soll nun ausgeführt werden:

[csharp] InitializeHashtable2();[/csharp]

Nun können wir einem Dritten einen Tipp geben, welches Passwort benny benutzt.

[csharp] string benutzer = “benny”;
Console.WriteLine(“Ein Tipp für das Passwort von ‘” + benutzer + “‘: ” + this.ht_tipp[this.ht_pass[benutzer].ToString()].ToString());
[/csharp]

oder besser:

[csharp]

string benutzer = “benny”;
Console.WriteLine(“Ein Tipp für das Passwort von ‘” + benutzer + “‘: ” + this.GetHashTableValueByIndey(this.ht_tipp, this.GetHashTableValueByIndey(this.ht_pass, benutzer)));
[/csharp]

Ausgabe:

Ein Tipp für das Passwort von ‘benny’: automarke

Die beiden Hashtables ht_pass und ht_tipp wurden verschachtelt. Der Wert von ht_pass mit dem Schlüssel benny ist der Schlüssel für einen Wert des Hashtable ht_tipp.

Die Verschachtelung über die Methode GetHashTableValueByIndey() ist sinnvoller, da diese eigenimplementierte Methode auf nicht vorhandene Schlüssel eingeht und eine Exception verhindert.

Ein Beispiel für einen nicht vorhandenen Schlüssel:

[csharp]

benutzer = “jens”;
Console.WriteLine(“Ein Tipp für das Passwort von ‘” + benutzer + “: ” + this.GetHashTableValueByIndey(this.ht_tipp, this.GetHashTableValueByIndey(this.ht_pass, benutzer)));

[/csharp]

Ausgabe:

Ein Tipp für das Passwort von ‘jens: [Wert-Schlüssel-Paar mit Schlüssel ‘[Wert-Schlüssel-Paar mit Schlüssel ‘jens’ existiert nicht]’ existiert nicht]

Nachfolgend den gesamten Quelltext im Zusammenhang:

[csharp] using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Text;

namespace ConsoleApplication_stack
{
public class Program
{
// Deklaration
Hashtable ht_pass;
Hashtable ht_tipp;

private Program()
{

// Instanziierung des Hashtable ht_pass

ht_pass = new Hashtable();

// Anlegen von Schlüssel-Werte-Paaren, ähnlich einem normalen Array

ht_pass[“benny”] = “porsche”;
ht_pass[“david”] = “programmierer”;
ht_pass[“thomas”] = “kaufmann”;
ht_pass[“daniela”] = “hamburg”;
ht_pass[“sarah”] = “universität”;

Console.WriteLine(this.ht_pass[“benny”].ToString());
Console.WriteLine(this.GetHashTableValueByIndey(this.ht_pass,”key1″));
Console.WriteLine(this.GetHashTableValueByIndey(this.ht_pass, “thomas”));

this.ShowAllItems(ht_pass);

InitializeHashtable2();

string benutzer = “benny”;
Console.WriteLine(“Ein Tipp für das Passwort von ‘” + benutzer + “‘: ” + this.ht_tipp[this.ht_pass[benutzer].ToString()].ToString());
Console.WriteLine(“Ein Tipp für das Passwort von ‘” + benutzer + “‘: ” + this.GetHashTableValueByIndey(this.ht_tipp, this.GetHashTableValueByIndey(this.ht_pass, benutzer)));

benutzer = “jens”;
Console.WriteLine(“Ein Tipp für das Passwort von ‘” + benutzer + “: ” + this.GetHashTableValueByIndey(this.ht_tipp, this.GetHashTableValueByIndey(this.ht_pass, benutzer)));
}

///

/// Liefert den Wert eines Hastables zurück
///

///Referenz des Hashtable ///Schlüssel /// Wert
private string GetHashTableValueByIndey(Hashtable ht, string key)
{
string return_string;

if (ht != null && ht.ContainsKey(key))
{
return_string = ht[key].ToString();
}
else
{
return_string = “[Wert-Schlüssel-Paar mit Schlüssel ‘” + key + “‘ existiert nicht]”;
}

return return_string;
}

private void InitializeHashtable2()
{
this.ht_tipp = new Hashtable();

this.ht_tipp.Add(“hamburg”, “stadt”);
this.ht_tipp.Add(“bmw”, “automarke”);
this.ht_tipp.Add(“porsche”, “automarke”);
this.ht_tipp.Add(“universität”, “öffentliche Einrichtung”);
}

private void ShowAllItems(Hashtable hashtable)
{
foreach (object key in hashtable.Keys)
{
Console.WriteLine(“Key: ” + key.ToString() + “; Value: ” + hashtable[key].ToString());
}
}

public static void Main()
{
Program programm = new Program();
}
}
}
[/csharp]