Ομαδοποίηση κατά σε LINQ

Ας υποθέσουμε ότι έχουμε μια κλάση όπως η

class Person { 
    internal int PersonID; 
    internal string car  ; 
}

Τώρα έχω μια λίστα αυτής της κλάσης: Λίστα<Person> persons;

Τώρα αυτή η λίστα μπορεί να έχει πολλαπλές περιπτώσεις με τα ίδια PersonIDs, για παράδειγμα:

persons[0] = new Person { PersonID = 1, car = "Ferrari" }; 
persons[1] = new Person { PersonID = 1, car = "BMW"     }; 
persons[2] = new Person { PersonID = 2, car = "Audi"    }; 

Υπάρχει τρόπος να ομαδοποιήσω με βάση το personID και να πάρω τη λίστα με όλα τα αυτοκίνητα που έχει;

Για παράδειγμα, το αναμενόμενο αποτέλεσμα θα ήταν

class Result { 
   int PersonID;
   List<string> cars; 
}

Έτσι, μετά την ομαδοποίηση, θα έπαιρνα:

results[0].PersonID = 1; 
List<string> cars = results[0].cars; 

result[1].PersonID = 2; 
List<string> cars = result[1].cars;

Από ό, τι έχω κάνει μέχρι στιγμής:

var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, // this is where I am not sure what to do

Θα μπορούσε κάποιος να μου δείξει τη σωστή κατεύθυνση;

Λύση

Απολύτως - βασικά θέλετε:

var results = from p in persons
              group p.car by p.PersonId into g
              select new { PersonId = g.Key, Cars = g.ToList() };

Ή ως έκφραση μη ερωτήματος:

var results = persons.GroupBy(
    p => p.PersonId, 
    p => p.car,
    (key, g) => new { PersonId = key, Cars = g.ToList() });

Βασικά, τα περιεχόμενα της ομάδας (όταν προβάλλεται ως IEnumerable) είναι μια ακολουθία οποιωνδήποτε τιμών υπήρχαν στην προβολή (p.car σε αυτή την περίπτωση) που υπάρχουν για το συγκεκριμένο κλειδί.

Για περισσότερες πληροφορίες σχετικά με τον τρόπο λειτουργίας του GroupBy, δείτε την ανάρτησή μου Edulinq post on the topic.

(Έχω μετονομάσει το PersonID σε PersonId στο παραπάνω κείμενο, για να ακολουθήσω τις .NET συμβάσεις ονοματοδοσίας).

Εναλλακτικά, θα μπορούσατε να χρησιμοποιήσετε ένα Lookup:

var carsByPersonId = persons.ToLookup(p => p.PersonId, p => p.car);

Στη συνέχεια, μπορείτε να βρείτε τα αυτοκίνητα για κάθε άτομο πολύ εύκολα:

// This will be an empty sequence for any personId not in the lookup
var carsForPerson = carsByPersonId[personId];
Σχόλια (18)
var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key,
                           /**/car = g.Select(g=>g.car).FirstOrDefault()/**/}
Σχόλια (0)
var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, Cars = g.Select(m => m.car) };
Σχόλια (0)