Autor |
Beitrag |
BlackMatrix
      
Beiträge: 243
Erhaltene Danke: 1
|
Verfasst: Fr 04.11.11 20:48
Guten Abend.
Ich möchte gerne, dass zu meiner generischen Liste<class> ein Element nur dann hinzugefügt wird, wenn eine Property der Klasse in der Liste noch nicht vorhanden ist.
Etwas kompliziert? Hier mein bisheriger Code:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| List<Klasse> Klassen = new List<Klasse>();
public bool AddIfNotExists(Klasse klasse) { if (!Contains(klasse)) { Proxies.Add(klasse); return true; } return false; }
public bool Contains(Klasse klasse) { if (Klassen.Where(k => k.Property== klasse.Property).Count() > 0) return true; return false; } |
Das funktioniert zwar soweit, aber wenn ich nun 1000 Elemente hinzufügen würde, dann dauert dies zulange, weil bei jedem Element über diese Linqausdruck geschaut wird, ob schon ein Element vorhanden ist.
Nun meine Frage, wie löst man am besten das Problem?
1. Hält man neben der Liste<Klasse> einfach noch eine Liste mit der Property der Klasse und prüft dann einfach mit der Methode von List nach Contains.
Ist meiner Meinung nach aber sehr umständlich, weil man immer aufpassen muss, dass beide Listen die selben Werte hat und man ja im Grunde doppelt Sachen speichert.
2. Man fügt erstmal alle Element hinzu und löscht am Ende die doppelten? Wobei man dann wieder aufpassen muss, dass man nicht die älteren Elemente entfernt. Unschön finde ich es auch -> erst hinzufügen, dann wieder löschen.
3. <Eure Meinung>
LG
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Fr 04.11.11 21:36
Hallo!
Ich würde das mit einem Dictionary lösen:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| class Klasse { public string Property { get; set; } }
class Liste { private Dictionary<string, Klasse> klassen = new Dictionary<string, Klasse>();
public bool AddIfNotExists(Klasse k) { if (klassen.ContainsKey(k.Property)) return false;
klassen.Add(k.Property, k); return true; } } |
Grüße,
Christian
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 04.11.11 22:53
Wenn Du zusätzlich IComparable implementierst kannst Du auch mit der Contains-Methode der Collections arbeiten, um zu prüfen, ob das Element schon drin ist. Außer Du brauchst eine genauere Prüfung unabhängig von dem einen Attribut an anderer Stelle.
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Fr 04.11.11 23:06
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
ujr
      
Beiträge: 102
Erhaltene Danke: 12
|
Verfasst: Fr 04.11.11 23:10
Christian S. hat folgendes geschrieben : | Ich würde das mit einem Dictionary lösen |
oder mit HashSet<T>, weil es zum "Key" keinen "Value" gibt und es entfällt jegliche Prüfung, da .Add Elemente nur einmalig hinzufügt.
PS: Wie kommt eigentlich der OffTopic-Anteil in den Sternchen zustande?
|
|
BlackMatrix 
      
Beiträge: 243
Erhaltene Danke: 1
|
Verfasst: Sa 05.11.11 01:02
|
|
ujr
      
Beiträge: 102
Erhaltene Danke: 12
|
Verfasst: Sa 05.11.11 01:18
BlackMatrix hat folgendes geschrieben : | HashSet added auch 2 völlig identische Objekte |
Was heißt das? Beachte, dass "2 völlig identische Objekte" immer noch zwei Objekte und nicht ein und das selbe sind. Du musst eben einen HashSet-Konstruktor nehmen, der den IEqualityComparer festlegt.
Poste doch mal Beispielcode.
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Sa 05.11.11 01:25
|
|
BlackMatrix 
      
Beiträge: 243
Erhaltene Danke: 1
|
Verfasst: Sa 05.11.11 01:29
Das mit dem IEqualityComparer hatte ich noch nicht gewusst, ich werde das morgen einmal ausprobieren.
Wenn ich z.B. 2 Objekte erzeuge, dann möchte ich, dass sich im HashSet nur eins befindet:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| class Person { public string Vorname{get;set;} Person(string vorname){Vorname=vorname;} }
Person p1=new Person("Hans"); Person p2=new Person("Hans"); HashSet.Add(p1); HashSet.Add(p2); |
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Sa 05.11.11 01:58
Mit dieser Klassenimplementation würde das funktionieren:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| class Person:IEquatable<Person> { public string Vorname { get; set; } public Person(string vorname) { Vorname = vorname; }
public override int GetHashCode() { return Vorname.GetHashCode(); }
public bool Equals(Person other) { return other.Vorname == this.Vorname; } } |
Und jetzt darf Christian als Experte noch etwas dazu sagen 
|
|
BlackMatrix 
      
Beiträge: 243
Erhaltene Danke: 1
|
Verfasst: Mo 07.11.11 00:00
Dank dir, ist implementiert und funktioniert.
|
|
ujr
      
Beiträge: 102
Erhaltene Danke: 12
|
Verfasst: Mo 07.11.11 10:55
Hallo,
ganz richtig ist es aber von der Objektorientierung her nicht. Zwei "Personen" sind eben nicht identisch, bloß weil sie den selben Vornamen haben. Diese Klasse könnte niemals anderweitig eingesetzt werden. Denn vielleicht will man ja woanders nach dem Geburtsdatum entscheiden?
Einen IEqualityComparer zu benutzen wäre meiner Meinung nach die deutlich bessere Lösung. Auch wenn der praktisch fast genauso aussehen würde. Aber man könnte für einen anderen Zweck einen anderen benutzen, die Person-Klasse bliebe aber gleich.
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Mo 07.11.11 11:06
ujr hat folgendes geschrieben : | Hallo,
ganz richtig ist es aber von der Objektorientierung her nicht. Zwei "Personen" sind eben nicht identisch, bloß weil sie den selben Vornamen haben. Diese Klasse könnte niemals anderweitig eingesetzt werden. Denn vielleicht will man ja woanders nach dem Geburtsdatum entscheiden?
Einen IEqualityComparer zu benutzen wäre meiner Meinung nach die deutlich bessere Lösung. Auch wenn der praktisch fast genauso aussehen würde. Aber man könnte für einen anderen Zweck einen anderen benutzen, die Person-Klasse bliebe aber gleich. |
Da hast Du vollkommen recht. Deswegen auch mein obiger Hinweis, dass dies nur sinnvoll ist, wenn generell damit die Gleichheit dieser Instanzen definiert werden kann.
|
|
VampireSilence
      
Beiträge: 109
Erhaltene Danke: 5
C# (VS 2008 Express), PHP/MySQL, Windows XP
|
Verfasst: Di 08.11.11 11:33
Ich denke beide Probleme (Wiederverwendbarkeit und Performance) lassen sich am besten mit einem Bisektionsverfahen lösen. Der Vergleichsmethode müsste dann lediglich noch ein Parameter übergeben werden, der die Property qualifiziert, welche als Vergleich dienen soll. Somit könnte man anschließend sowohl gleiche Vornamen, als auch Nachnamen oder sonstwas vergleichen.
Davon abgesehen, könntest du auch für die Kombination aus Vor- und Nachnamen einen Hash vorberechnen, der dann verglichen werden kann, um eben die Kombination ausschließen zu können, ohne 2 gesonderte Vergleiche über die gesamte Liste anstellen zu müssen.
mfg
- VampireSilence
|
|