hallo zusammen
ich habe kein eigentliches problem, sonden eher eine frage nach einer etwas eleganteren lösung.
ich habe eine klasse 'Relation', die folgende properties hat:
(alles strings)
in einer anderen klasse habe ich eine ArrayList 'relations_', sowie die folgende methode:
public void DeleteRelation(string relationName)
{
foreach(Relation r in this.relations_)
{
if(r.RelationName == relationName)
{
this.relations_.RemoveAt(this.relations_.IndexOf(r));
break;
}
}
wie ihr seht löscht diese methode die Relation aus der ArrayList, die den angegebenen 'RelationName' besitzt.
nun zu meiner frage: kann ich dies nicht ein bisschen eleganter lösen? irgendwie stört mich die zeile
this.relations_.RemoveAt(this.relations_.IndexOf(r));
🤔
thx im voraus für vorschläge
Ich würde folgendes vorschlagen, das auch das (bei einer grossen Anzahl von Einträgen) unperformante foreach() durch for() ersetzt.
public void DeleteRelation(string relationName)
{
for (int i = 0; i < this.relations_.Count; i++)
{
Relation r = (Relation) this.relations_[i];
if (r.RelationName == relationName)
{
this.relations_.RemoveAt(i);
break;
}
}
}
foreach(Relation r in this.relations_)
{
if(r.RelationName == relationName)
{
this.relations_.Remove(r);
break;
}
}
this.relations_.Remove(r);
aber warum übergibst du nicht das relation object, das aus der liste gelöscht werden soll? oder wäre vielleicht eine hashtable eine bessere wahl?
erstmal vielen dank. das überrascht mich immer wieder, wie schnell in dieser community geantwortet wird! 👍
das mit der for-schleife werde ich mir genauer anschauen. wäre eine hübsche lösung.
Original von Xqgene
aber warum übergibst du nicht das relation object, das aus der liste gelöscht werden soll? oder wäre vielleicht eine hashtable eine bessere wahl?
ich will eben, dass man nur den RelationName übergeben kann. es ist sichergestellt, dass ein RelationName nur einmal vorkommt, daher wird dies keine probleme geben.
mit hashtables habe ich gar keine erfahrungen (weiss ehrlichgesagt nicht mal genau was das ist/wo sie angewendet werden).
kannst du mir das etwas genauer erläutern?
@bitstream: dein code könnte aber auch noch optimiert werden. etwa so:
public void DeleteRelation(string relationName)
{
for (int i = 0; i < this.relations_.Count; i++)
{
//Relation r = (Relation) this.relations_[i];
if (((Relation)this.relations_[i]).RelationName == relationName)
{
this.relations_.RemoveAt(i);
break;
}
}
}
oder ist dies nicht klug?
Original von RIDI2oo5
@bitstream: dein code könnte aber auch noch optimiert werden. etwa so:
Das würde ich nicht als Optimierung ansehen. Und besser finde ich es auch nicht, da es (zumindest für meinen Geschmack) es schlechter lesbar ist. Kurz gesagt, es war Absicht, das aktuelle Relation-Objekt in einer separaten Variable zu halten.
Xgene schrieb ausserdem: "oder wäre vielleicht eine hashtable eine bessere wahl?". Das wäre wirklich zu überlegen, eine Collection einzusetzen, bei der du den Relation-Namen als Schlüssel verwendest. Dann brauchst du gar keine Schleife mehr...
wie gesagt, ich habe null erfahrung im umgang mit hashtables. aber ich werde mich mal darüber informieren. findet sich sicher eine menge darüber in dieser community 😉
nochmals:
thx a lot 👍
<edit>
hab's jetzt übrigens vorübergehend mit der for-schleife gelöst. allerdings ohne das aktuelle Relations-objekt in eine separate variable zu speichern. ich bin mir den anblick von 'castings' (scheiss DSDSS 😉 ) schon sehr gewöhnt, da ich sie sehr viel benütze. von dem her erschein mir der code so gut lesbar.
aber das ist denke ich geschmacksache 🤔
</edit>
Deine for i = ... Schleife funktioniert so gut:
Du solltest aber eines dabei beachten: Das BREAK muss unbedingt sein, da durch das Löschen die Indizierung verändert wird.
PS: Ob HashTables oder ArrayList - musst Du entscheiden: was gespeichert werden soll und vor allem: wie darauf zugegriffen werden soll.
HashTables machen dann erst richtig Sinn, wenn Du eine indizierte Elementsuche brauchst (halt über die Hashes....).
Warum so einfach, wenn's auch kompliziert geht !
Original von Heron
Deine for i = ... Schleife funktioniert so gut:
Du solltest aber eines dabei beachten: Das BREAK muss unbedingt sein, da durch das Löschen die Indizierung verändert wird.
da hast du recht. das habe ich mir noch gar nicht überlegt.
obwohl es bei diesem konkreten beispiel so wie ich das sehe nichts ausmachen würde, da ich ja nicht nach einem bestimmten index suche, sondern eben nach dem 'RelationName' eines objekts.
ein zweiter grund, warum das 'break;' dasein sollte ist der, dass die 'suche' ja nach dem ersten fund abgeschlossen ist. warum also die restlichen objekte in der auflistung auch noch durchgehen, wenn man schon hat was man will.
<edit>
ach so, jetz weiss ich was du meinst mithammeraufkopfschlag 👅
na klar, du hast recht! es würde ein eintrag übersprungen werden, wenn ich es ohne 'break;' lösen würde. 😁
...und irgendwann zu allem überfluss noch eine 'IndexOutOfRange'-Exception 😉
</edit>
was für "IndexOutOfRange"??
in dem schleifenkopf wird der index doch geprüft.
Original von Xqgene
was für "IndexOutOfRange"??in dem schleifenkopf wird der index doch geprüft.
Mal lesen: Wenn in der Liste gelöscht wird - dann eben nicht mehr !!!
Warum so einfach, wenn's auch kompliziert geht !
Wenn in der Liste gelöscht wird, dann ändert sich auch relations_.Count. und das wird in dem schleifen kopf vor jedem loop geprüft.
ach so, das habe ich nicht gewusst. ich habe gedacht das würde am anfang der schlaufe einmal überprüft und dann immer dieser wert verwendet.
naja, dann eben keine exception 😜 😉
aber ein objekt übersprungen wird trotzdem 8)
Hallo RIDI2oo5,
ich habe null erfahrung im umgang mit hashtables
siehe Grundlegendes zu Hashtables
herbivore
Mit Hashtables arbeiten ist total einfach. Wirst es nicht bereuen dir das reinzuziehen. Zumal das dein Problem erschlägt.
hey vielen dank!
ich habe mir die beispiele angeschaut. jetzt verstehe ich endlich den verwendungszweck von hashtables. war vorher immer eher ein mysterium X(
ps.: hmm... hab lange nicht geantwortet. dieser thread wurde mir nicht als 'ungelesen' markiert 🤔
hallo zusammen
ich habe nochmal eine kleine frage zum thema hashtables, die mir in hauptmanns tut nicht so recht klar wurden.
wenn ich mal den code von hauptmann als beispiel nehme:
public class MyClass
{
private String _strId;
private static Hashtable _htAlleObjekte = new Hashtable ();
public MyClass (String strId)
{
_strId = strId;
_htAlleObjekte [_strId] = this;
}
public static MyClass GibObjektZuId (String strId)
{
return (MyClass)_htAlleObjekte [strId];
}
}
wie bestimme ich, welche property nun als indizier verwendet wird?
wenn ich nun noch ein paar properties mehr in meiner klasse hätte...
public class MyClass
{
private String _strId;
private String _strId2;
private String _strId3;
private String _strId4;
private static Hashtable _htAlleObjekte = new Hashtable ();
public MyClass (String strId)
{
_strId = strId;
_htAlleObjekte [_strId] = this;
}
public static MyClass GibObjektZuId (String strId)
{
return (MyClass)_htAlleObjekte [strId];
}
}
bestimme ich nun beim hinzufügen ein objektes zur hashtable, was ich als indizier verwenden will? ich könnte ja das objekt auch mit
_htAlleObjekte[_strId2] = this;
hinzufügen.
oder bestimmt man einfach, dass der indizier z.b. ein string sein soll?
ihr seht, ich habe dringenden erklärungsbedarf... X(
Hallo RIDI2oo5,
in dem Beispiel geht es darum, dass man an die Objekte über ihre Id herankommt. Aus dieser Aufgabenstellung - und nur daraus ergibt sich -, dass strId als "Index" (besser Key) der Hashtable benutzt wird.
Von der Hasttable aus, kann jedes beliebige Objekt als Key verwendet werden. Ok, wenn man es genau nimmt, stellt die Hashtable schon einige Anforderungen an ihre Key-Objekte, z.B. dass sie ihren Zustand nicht ändern (können), aber die Objekte, die man als Key wählt - also bei denen man auf den Gedanken kommt, sie als Key zu verwenden - erfüllen die Eigenschaften meist automatisch. Gängigerweise sind die Keys ohnehin Strings.
Ich bin mir nicht sicher, ob das deine Frage vollständig klärt.
herbivore
PS: Das Tutorial und der Code sind von mir. 🙂
Die Elemente einer Hashtable haben immer einen Schlüssel, den du entweder bei Add() als ersten Parmeter oder an den Indexer als Index übergibst. Im Beispielcode ist das immer der Wert der in strId drinsteht. Mit _htAlleObjekte[strId] greifst du also immer auf das Element zu, welches durch den Schlüssel strId identifiziert wird.
Der Schlüssel ist vom Typ System.Object, kann also beliebig sein. Der Schlüssel ist keine bestimmte Property deines Objekts, da die Hashtable die Logik deiner Objekte bzw. deren Klassen nicht kennt. Es ist also deine freie Entscheidung, woher dieser Schlüssel kommt und wo du diesen speicherst. Der Einfachheit halber bietet es sich logischerweise an, diesen in einem Instanzfeld des Objekts zu speichern und als Property ohne Setter zur Verfügung zu stellen. Es obliegt dann aber immer noch dir selbst, der Hashtable zu sagen, welcher Schlüsselwert zu verwenden ist, da die Hashtable diesen Umstand nicht kennen kann.
hallo zusammen
erstmal: vielen dank für die erneute erklärung. brauche halt manchmal ein bisschen länger... =)
ich habe inzwischen noch ein wenig ausprobiert und bin dabei selber darauf gekommen. mein fehler war, anzunehmen, dass der key immer im objekt enthalten sein muss.
aber als ich den begriff key-value-collection gelesen habe, war es mir klar...
Original von herbivore
PS: Das Tutorial und der Code sind von mir. 🙂
oops... sorry herbivore =)