Groupe par dans LINQ
Supposons que si nous avons une classe comme
class Person {
internal int PersonID;
internal string car ;
}
Maintenant, j'ai une liste de cette classe: List<Person> persons;
Maintenant cette liste peut avoir plusieurs instances du même PersonIDs, par exemple:
persons[0] = new Person { PersonID = 1, car = "Ferrari" };
persons[1] = new Person { PersonID = 1, car = "BMW" };
persons[2] = new Person { PersonID = 2, car = "Audi" };
Est-il une manière que je peux groupe par personID
et obtenir la liste de toutes les voitures qu'il a?
Par exemple, le résultat attendu serait
class Result {
int PersonID;
List<string> cars;
}
Donc après regroupement, je voudrais obtenir:
results[0].PersonID = 1;
List<string> cars = results[0].cars;
result[1].PersonID = 2;
List<string> cars = result[1].cars;
De ce que j'ai fait jusqu'à présent:
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
Quelqu'un pourrait-il svp me pointer dans la bonne direction?
- dans l'esprit de pedanticism, une adresse est à peu près autant d'une propriété intrinsèque de la personne de leur voiture. aussi, on ne serait sans doute de stocker leur date de naissance plutôt que de l'âge.
- Il est un autre exemple dont
Count
etSum
ici stackoverflow.com/questions/3414080/... - Källman: je suis d'accord avec Chris Walsh. Les plus susceptibles d'une application qui a l'O. P. "Personne(s)" de la Classe (Table) auraient déjà un ""normal "" "Personne(s)" de la Classe (Tableau) qui a l'usu. Propriétés / Colonnes (nom, sexe, date de naissance). L'O. P. "Personne(s)" de la Classe (Table) serait pro être un Enfant de la Classe (Tableau) de la ""normal "" "Personne(s)" de la Classe ( Tableau) (c'est à dire un "OrderItem(s)" de la Classe (Tableau) par rapport à une "Commande(s)" de la Classe (Tableau)). L'O. P. a probablement pas utiliser le nom qu'il avait utiliser si elle était dans le même Champ d'application que son ""normal "" "Personne(s)" de la Classe (Tableau) et/ou peuvent l'ai simplifié pour ce post.
Vous devez vous connecter pour publier un commentaire.
Absolument - en gros, vous voulez:
Ou de la non-expression de requête:
Fondamentalement le contenu du groupe (lors de l'afficher comme un
IEnumerable<T>
) est une séquence de quelles que soient les valeurs étaient dans la projection (p.car
dans ce cas) présents pour la clé donnée.Pour en savoir plus sur la façon dont
GroupBy
œuvres, voir mon Edulinq post sur le sujet.(Je l'ai renommé
PersonID
àPersonId
ci-dessus, à suivre .NET des conventions de nommage.)Sinon, vous pouvez utiliser un
Lookup
:Vous pouvez ensuite obtenir les voitures pour chaque personne très facilement:
.GroupBy(p => new {p.Id, p.Name}, p => p, (key, g) => new { PersonId = key.Id, PersonName = key.Name, PersonCount = g.Count()})
et vous obtiendrez toutes les personnes qui se produisent avec un Id, Nom, et un certain nombre d'occurrences pour chaque personne.var
, vous devez mettre le type réel de résultats, pour être encore plus clair sur ce que ce n'/crée.SortedDictionary <PersonIdInt, SortedDictionary <CarNameString, CarInfoClass>>
. Le plus proche que je pouvais obtenir de l'aide de LINQ a étéIEnumerable <IGrouping <PersonIdInt, Dictionary <CarNameString, PersonIdCarNameXrefClass>>>
. J'ai fini à l'aide de @akazemis defor(each)
méthode de boucle qui, d'ailleurs, était 2x plus vite (et bien sûr, plus facile à déboguer).Lookup
pour cette réponse, qui, je pense, serait l'approche la plus simple...Lookup
Propriétés.SortedDictionary
sont O(log n).Lookup
avoir O(1) l'accès, comme je l'avais espérer qu'il soit basé sur uneDictionary<,>
ou similaire. Voir codeblog.jonskeet.royaume-uni/2010/12/31/... pour plus de détails.Lookup
O(1) (et je ne vois pas comment il pourrait l'être, sauf si la Clé se trouve être un entier de Type et se trouve être ascendante par rapport à la commande d'insertion et séparés par le même incrément (aucun (sauf pour le Type) par la / spécifié àLookup
), ce qui pourrait être formulaicly résolu dans un Index de Tableau en supposant que c'est même stocké dans un Tableau), il semble que l'utilisation de il permettrait seulement efficace look-ups d'un PersonId vs aussi un CarName après récupération de PersonId de CarNames.PersonId
, mais vous aurez toujours besoin d'accéder à d'autres propriétés dePerson
?p.car
àp
dans l'exemple de mon code, et que vous souhaitez jusqu'à la fin avec des groupes dePerson
éléments.Vous pouvez également Essayer cette.
essayer
ou
pour vérifier si une personne est de répéter dans votre liste d'essayer
J'ai créé un exemple de code avec la Syntaxe de la Requête et de la Méthode de la Syntaxe. J'espère que cela aide les autres 🙂
Vous pouvez également exécuter le code sur .Net Violon ici:
Voici le résultat:
Essayez ceci :
Mais en terme de performance suivantes pratique est mieux et plus optimisé l'utilisation de la mémoire (lors de notre tableau contient beaucoup plus d'éléments, comme des millions):
g.Key.PersonId
?g.SelectMany
?? De toute évidence, vous n'essayez pas de le faire.SortedDictionary <PersonIdInt, SortedDictionary <CarNameString, CarInfoClass>>
. Le plus proche que je pouvais obtenir de l'aide de LINQ a étéIEnumerable <IGrouping <PersonIdInt, Dictionary <CarNameString, PersonIdCarNameXrefClass>>>
. J'ai fini à l'aide de votrefor
méthode de boucle qui, d'ailleurs, était 2x plus rapide. Aussi, je voudrais utiliser: a)foreach
vsfor
et b)TryGetValue
vsContainsKey
(SÈCHES principe - dans le code & runtime).Une autre façon de faire pourrait être select distinct
PersonId
et du groupe de la jointure avec lepersons
:Ou même avec l'API fluent syntaxe:
GroupJoin produit une liste d'entrées dans la première liste ( liste de
PersonId
dans notre cas), chacun avec un groupe d'entrées jointes dans la deuxième liste (liste depersons
).