.NETte Dinge und noch einiges mehr ;-) RSS 2.0
 Wednesday, March 29, 2006

Beim Entwickeln bin ich bisher auf das Problem gestoßen, dass ich einen Wert innerhalb einer Liste anhand von mehreren zusammengesetzten Schlüsseln identifizieren muss. Eine Hashtable bietet von "Natur" aus aber leider nur einen möglichen Schlüssel. Eine Möglichkeit wäre natürlich sich einen Schlüssel "zusammenzuparsen".

Ein weitere Möglichkeit, und wie ich finde auch die elegantere Methode ;-), ist die Folgende. Ausgangspunkt ist hier eine Hashtable welches als Schlüssel den ersten Teil des zusammengesetzten Schlüssel besitzt. Als Wert ist wiederum eine Hashtable eingefügt, welche den zweiten Teil des Schlüssel zur Identifierung besitzt. Und so geht das Spiel runter bis zum letzten Schlüssel.

Der Vorteil ist, dass die MultiKeyHashtable nicht auf eine feste Schlüsselanzahl begrenzt ist. Was die Effizienz anbelangt, habe ich noch keine intensiven Tests durchführen können. Doch da innerhalb der Hashtables mit Referenzen gearbeitet wird, kann es nur schnell sein ;-).


using System;
using System.Collections;
namespace MultiKeyHashtable
{
/// <summary>
/// Ermöglicht das Speichern von Werten mit mehreren zusammengesetzten Schlüsseln
/// </summary>
public class MultiKeyHashtable
{
private Hashtable _Root;
private int _KeysCount;

/// <summary>
/// Legt eine neue Instanz an
/// </summary>
/// <param name="keysCount">Anzahl der Schlüssel, die zusammen eindeutig sein müssen</param>
public MultiKeyHashtable(int keysCount)
{
this._KeysCount = keysCount;
if (keysCount > 0)
{
this._Root = new Hashtable();
}
else
{
throw new FormatException("Die Schlüsselanzahl der MultiKeyHashtable muss größer null sein. Wert: " + keysCount);
}
}

/// <summary>
/// Ermöglicht das Einfügen bzw. das Auslesen von Schlüssel- / Wertpaaren
/// </summary>
public object this [params object[] keys]
{
get
{
if (this.CheckKeyCount(keys.Length))
{
return this.GetValue(this._Root, 0, keys);
}
return null;
}
set
{
if (this.CheckKeyCount(keys.Length))
{
this.SetValue(this._Root, 0, value, keys);
}
}
}

/// <summary>
/// Fügt für den angegebenen Schlüssel den Wert ein
/// </summary>
/// <param name="value"></param>
/// <param name="keys"></param>
public void Add(object value, params object[] keys)
{
if (this.CheckKeyCount(keys.Length))
{
this.SetValue(this._Root, 0, value, keys);
}
}

/// <summary>
/// Überprüft ob ein Schlüssel vorhanden ist oder nicht
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
public bool ContainsKey(params object[] keys)
{
if (this.CheckKeyCount(keys.Length))
{
if (this.GetValue(this._Root, 0, keys) != null)
{
return true;
}
}
return false;
}

/// <summary>
/// Entfernt für den angegebenen Schlüssel den eingetragenen Wert
/// </summary>
/// <param name="keys">zusammengesetzt eindeutiger Schlüssel</param>
public void Remove(params object[] keys)
{
if (this.CheckKeyCount(keys.Length))
{
this.RemoveValue(this._Root, 0, keys);
}
}

private bool CheckKeyCount(int count)
{
if (count == this._KeysCount)
{
return true;
}
else
{
throw new FormatException("Die Parameteranzahl (" + count + ") stimmt nicht mit der initialen Schüsselanzahl (" + this._KeysCount + ") überein. ");
}
}


private object GetValue(Hashtable currentHt, int counter, params object[] keys)
{
if (currentHt.ContainsKey(keys.GetValue(counter)))
{
int c = this._KeysCount;
if (counter == c--)
{
//Wert vorhanden, Ende erreicht, Value zurückgeben
return currentHt[keys.GetValue(counter)];
}
else
{
//Wert vorhanden --> weiter in die Tiefe gehen
Hashtable nextHt = currentHt[keys.GetValue(counter)] as Hashtable;
this.GetValue(nextHt, counter + 1, keys);

//sollte nicht eintreffen durch die Rekursion
return null;
}
}
else
{
//Wert wurde nicht gefunden
return null;
}
}


private Hashtable SetValue(Hashtable currentHt, int counter, object value, params object[] keys)
{
if (!currentHt.ContainsKey(keys.GetValue(counter)))
{
//Wert nicht vorhanden
int c = this._KeysCount - 1;
if (counter == c)
{
//Ende erreicht
currentHt.Add(keys.GetValue(counter), value);
return currentHt;
}
else
{
//nächste Hashtable hinzufügen
currentHt.Add(keys.GetValue(counter), this.SetValue(new Hashtable(), counter + 1, value, keys));
return currentHt;
}
}
else
{
//key bereits vorhanden
int c = this._KeysCount - 1;
if (counter == c)
{
//Ende erreicht
throw new ArgumentException("Der Key ist bereits vorhanden.");
}
else
{
Hashtable nextHt = currentHt[keys.GetValue(counter)] as Hashtable;
currentHt.Remove(keys.GetValue(counter));
currentHt.Add(keys.GetValue(counter), SetValue(nextHt, counter + 1, value, keys));
}
}
//SetValue ist abgearbeitet
return null;
}


private void RemoveValue(Hashtable currentHt, int counter, params object[] keys)
{
if (currentHt.ContainsKey(keys.GetValue(counter)))
{
int c = this._KeysCount;
if (counter == c--)
{
//Wert vorhanden, Ende erreicht, löschen
currentHt.Remove(keys.GetValue(counter));
}
else
{
//vorhanden und löschen
Hashtable nextHt = currentHt[keys.GetValue(counter)] as Hashtable;
this.RemoveValue(nextHt, counter + 1, keys);
}
}
}
}
}

Wednesday, March 29, 2006 9:13:29 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0] -
.NET
Comments are closed.
Archive
<January 2009>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2009
Christian Stein
Sign In
Statistics
Total Posts: 238
This Year: 0
This Month: 0
This Week: 0
Comments: 20
All Content © 2009, Christian Stein
DasBlog theme 'Business' created by Christoph De Baene (delarou)