Autor Beitrag
BlackMatrix
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243
Erhaltene Danke: 1



BeitragVerfasst: Mi 14.03.12 23:29 
Guten Abend.

Was ist denn an der Syntax falsch?

Ich habe ein Dictionary<Id, List<Person>() und möchte gerne, die Id's haben, wo sich die Person, die ich als Parameter übergebe in der Liste befindet:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
        private Dictionary<Id, List<Person>> _d = new Dictionary<Id, List<Person>>();

        public Person GetNewPerson(Person person)
        {
            var ids = _d.Values.Where(list => list.Where(listPerson => listPerson == person));
            // [...]
        }


Das klappt auch nicht:
ausblenden C#-Quelltext
1:
            var ids = _d.Where(kvp => kvp.Value.Where(listPerson => listPerson == person));					
Eine Konvertierung von IEnumerable<Person> in bool ist nicht möglich...

Es ist irgendwie zum Mäuse melken.

LG
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 15.03.12 10:19 
Hallo BlackMatrix,

mittels Where wird dir ja eine Liste (IEnumerable<...>) zurückgegeben, die Bedingung innerhalb muß aber einen boolschen Ausdruck zurückgeben - daher kannst du diese Where-Methoden so nicht direkt verschachteln.

Suchst du
ausblenden C#-Quelltext
1:
var lists = _d.Values.Where(list => list.Contains(person));					

?

Edit: du suchst ja die Ids, also (ungetestet ;-))
ausblenden C#-Quelltext
1:
2:
var keyValuePairs = _d.Where((id, list) => list.Contains(person)); // beachte: kein 'Values' mehr
var ids = keyValuePairs.Select((id, list) => id);
BlackMatrix Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243
Erhaltene Danke: 1



BeitragVerfasst: Fr 16.03.12 19:54 
Irgendwie klappt das noch nicht so ganz.

Ich habe das IEquatable<Person> Interface bei meiner Personklasse implementiert und GetHashCode und Equals überschreiben.

Nur wenn ich jetzt             var lists = _d.Values.Where(list => list.Contains(person)); aufrufe, dann stoppt der Debugger weder bei Equals noch bei GetHashCode und dadurch enthält meine Ergebnisliste auch immer 0 Einträge.

Genau, ich suche die IDs.

Edit: dein 2. Snippet funktioniert nicht, da die Parameter nicht id und list sind, sondern nur das dictionary.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 16.03.12 20:34 
Hallo BlackMatrix,

Contains vergleicht nur auf Referenzen. Für Gleichheit (mittels Equals) könntest du die Linq-Methode Any benutzen:
ausblenden C#-Quelltext
1:
var lists = _d.Values.Where(list => list.Any(p => p == person));					

Edit: ich gehe davon aus, daß du auch den ==-Operator überschrieben hast, s.a. Richtlinien zum Überschreiben von Equals() und des Operators == - ansonsten einfach list.Any(p => p.Equals(person)) verwenden (ich selber mag diese Schreibweise aber nicht).

P.S. nun habe ich auch das mit den Ids ausprobiert:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
Dictionary<int, List<string>> _d = new Dictionary<int, List<string>>()
{
  { 1new List<string>() { "Axel""Bert" } },
  { 2new List<string>() { "Axel""Tom" } },
  { 3new List<string>() { "Axel""Bert" } },
  { 4new List<string>() { "Tom" } },
};

string person = "Tom";

var keyValuePairs = _d.Where(kvp => kvp.Value.Contains(person));
var ids = keyValuePairs.Select(kvp => kvp.Key);

// => { 2, 4 }

(statt einem Tupel wird ja ein KeyValuePair zurückgegeben und dann kann man auf Key bzw. Value zugreifen.)

Jetzt mußt du nur noch beides kombinieren...
BlackMatrix Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.03.12 15:14 
Vielen Dank für deine Antwort.

Irgendwie funktioniert es immer noch nicht und ich verstehe nicht warum.

Bei der Ausführung von var keyValuePairs = _d.Where(kvp => kvp.Value.Contains(peron)); kommt es nicht zum Aufruf von Equals oder GetHashCode meiner Personenobjekte, obwohl bei beiden Haltepunkte eingefügt worden sind.

Meine Personklasse implementiert das IEquatable<Person> Interface und überschreibt darin die beiden Methoden, jedoch erhalte ich immer eine leer Auflistung bei der erste Linqanweisung.

Noch eine kleine Bemerkung zu meinem Vorhaben, evtl. gehe ich das Ganze auch falsch an und die Linqabfragen würden gar nicht von Nöten sein.

Und zwar möchte ich gerne, dass meine Personen in einer bestimmten Reihenfolge getestet werden, der Test dauert immer etwa (0-30 Sekunden) wodurch ich mit der Linqanweisung immer erst die jetzt zu testenden Personen raussuche, dann mit einer Parallel.ForEach Schleife die einzelnen Personen teste und dann jeweils zur nächsten Linqanweisung (also der nächste Filter für mein Dictionary) ausgeführt wird und wieder getestet wird.

Nun hatte ich mir überlegt, anders vorzugehen, indem ich nicht mehr nacheinander erst eine Linqanweisung und dann den Test ausführe, sondern erst meine Personen in einer Liste so (vor)sortiere, dass ich erst danach die Tests mache.
Ein kleiner Hinweis noch, sobald ein Test erfolgreich war, verlasse ich die Parallel.ForEach Schleife mit loopState.Stop

LG
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 24.03.12 16:07 
Hallo BlackMatrix,

ich habe doch geschrieben, daß Contains nur auf Referenzen prüft und du daher den '=='-Operator (bzw. direkt Equals) innerhalb der Where-Methode benutzen sollst.

Dies meinte ich mit "beides kombinieren":
ausblenden C#-Quelltext
1:
var keyValuePairs = _d.Where(kvp => kvp.Value.Any(p => p == person));					
BlackMatrix Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243
Erhaltene Danke: 1



BeitragVerfasst: Mi 28.03.12 20:09 
Also irgendwas stimmt da noch nicht.

Kann es sein, dass ich noch irgendein Interface bei meiner Accountklasse implementiert werden muss? Denn es wird kein Equals aufgerufen. Normalerweise müsste diese Linqanweisung doch jedes Element meiner Liste durchgehen und prüfen, ob es der Person entspricht (Equals). Das tut es leider nicht.

Evtl. sollte man mein Problem auch anders lösen (siehe letzten Post)?

Okay, evtl. implementiere ich auch das GetHashCode und Equals falsch?

Wie implementiert man denn GetHashCode und Equals bei einem Objekt, dass nur aus 2 string eindeutig bzw. Ein und das Selbe ist?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 29.03.12 09:52 
Hallo BlackMatrix,

wie sieht denn jetzt dein aktueller Code aus? Hast du auch das "Edit" in meinem zweiten Beitrag hier gelesen (also daß du auch den ==-Operator implementieren solltest).
BlackMatrix Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243
Erhaltene Danke: 1



BeitragVerfasst: Do 29.03.12 13:21 
Ich kann leider erst heute Abend wieder an meinen Rechner, aber mir ist eingefallen, dass ich evtl. das falsche Equals implementiert habe?

Worin besteht denn der Unterschied, ob ich IEquatable<Person> implementiere

ausblenden C#-Quelltext
1:
2:
3:
4:
    public bool Equals(Person other)
    {

    }


oder ob ich Equals überschreibe? Hier könnte evtl. der Fehler liegen.

Deinen Code aus dem Edit habe ich versucht zu benutzen, der hat nicht funktioniert. Ich habe dann auch mal ganz klassisch versucht mit einer foreach Schleife durch die Values (List<Person>) zu steppen und die Liste auf Contains abzufragen, aber nie bekam ich ein true zurück.