Laden...

Elegantere Lösung zum löschen aus ArrayList

Erstellt von RIDI2oo5 vor 18 Jahren Letzter Beitrag vor 18 Jahren 6.210 Views
RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren
Elegantere Lösung zum löschen aus ArrayList

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:

  • RelationName
  • ParentTable
  • ParentField
  • ChildTable
  • ChildField

(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

B
189 Beiträge seit 2004
vor 18 Jahren

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;
		}
	}
}
N
4.644 Beiträge seit 2004
vor 18 Jahren
foreach(Relation r in this.relations_)
     {
          if(r.RelationName == relationName)
          {
               this.relations_.Remove(r);
               break;
          }
    }
X
2.051 Beiträge seit 2004
vor 18 Jahren
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?

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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?

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

@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?

B
189 Beiträge seit 2004
vor 18 Jahren

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...

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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>

H
63 Beiträge seit 2005
vor 18 Jahren

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 !

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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>

X
2.051 Beiträge seit 2004
vor 18 Jahren

was für "IndexOutOfRange"??

in dem schleifenkopf wird der index doch geprüft.

H
63 Beiträge seit 2005
vor 18 Jahren

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 !

X
2.051 Beiträge seit 2004
vor 18 Jahren

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.

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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)

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo RIDI2oo5,

ich habe null erfahrung im umgang mit hashtables

siehe Grundlegendes zu Hashtables

herbivore

S
8.746 Beiträge seit 2005
vor 18 Jahren

Mit Hashtables arbeiten ist total einfach. Wirst es nicht bereuen dir das reinzuziehen. Zumal das dein Problem erschlägt.

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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 🤔

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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(

49.485 Beiträge seit 2005
vor 18 Jahren

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. 🙂

B
189 Beiträge seit 2004
vor 18 Jahren

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.

RIDI2oo5 Themenstarter:in
140 Beiträge seit 2005
vor 18 Jahren

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 =)