3
votes

Groupe LINQ par plusieurs attributs et créer un dictionnaire

J'ai une liste d'objets d'une classe appelée ScrewBoltPattern .

Je souhaite créer un dictionnaire qui contient le nombre d'apparitions de chaque famille de ScrewBoltPattern . Pour décider si une vis appartient à une famille, j'utilise certaines propriétés de cette classe.

Pour simplifier cette requête, disons que j'utilise les propriétés Longueur et Diamètre.

Je veux créer un Dictionnaire dont les clés sont formatées comme vis.Longueur + "_" + vis.Diamètre

Comment puis-je obtenir cela?

C'est ce que j'ai fait jusqu'à présent

Dictionary<string, int> boltFamilyList = selectedBolts
                .GroupBy(bolt => new { bolt.Length, bolt.Diameter })
                .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

J'ai besoin de donner un format à la clé du dictionnaire quelque part, mais je ne sais pas comment faire.


0 commentaires

4 Réponses :


5
votes

Vous pouvez formater la clé du groupe par:

Dictionary<string, int> boltFamilyList = selectedBolts
    .GroupBy(bolt => $"{bolt.Length}_{bolt.Diameter}")
    .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

Votre clé de groupe (et par proxy votre clé de dictionnaire) sera cette chaîne formatée.

Essayez-le en ligne


4 commentaires

Et où dois-je spécifier les propriétés que je souhaite utiliser pour les regrouper?


Regroupez-vous selon différentes propriétés de votre clé formatée? Si tel est le cas, pouvez-vous modifier votre question pour refléter cela?


@Non, je ne suis pas. Est-ce que ça va le faire?


Le code que j'ai fourni sera regroupé par la valeur de chaîne générée par $ "{bolt.Length} _ {bolt.Diameter}" , qui sera également votre clé dans le dictionnaire. Cela devrait fonctionner comme prévu.



4
votes

Vous pouvez également utiliser un ILookup pour atteindre le même objectif:

int count = lookup["12_36"].Count();

puis

ILookup<string, int> lookup = 
    selectedBolts.ToLookup(bolt => $"{bolt.Length}_{bolt.Diameter}");


4 commentaires

Ce qui présente l'avantage de ne pas obtenir d'exception comme avec un dictionnaire si la clé n'est pas présente et vous pouvez utiliser d'autres méthodes en dehors de Count


@Rango En effet, + ce code évite la double énumération (boulons et entrées GroupBy) dans le code de l'OP. La gestion de la clé nulle pourrait également être pratique, mais pas dans ce cas.


Je ne pense pas que ce soit plus efficace que le code d'OP. ToLookup doit énumérer la liste et créer des groupes par une clé comme le fait GroupBy + ToDictionary , juste dans une méthode au lieu de deux mais avec la même complexité. Mais c'est plus flexible car il permet d'évaluer plus que le décompte si vous le souhaitez, sans créer de nouveau dictionnaire.


@Rango Sauf que ToDictionary doit vérifier si chaque entrée existe déjà. Je suis d'accord, ce n'est pas grave cependant.



1
votes

Bien que vous ayez déjà la solution, je veux juste indiquer comment vous pourriez la résoudre car vous étiez vraiment proche de la solution ...

.ToDictionary(bolt => $"{bolt.Key.Length}_{bolt.Key.Diameter}", bolt => bolt.Count());

dans la ligne de liste, vous pouvez créer la clé:

Dictionary<string, int> boltFamilyList = selectedBolts
    .GroupBy(bolt => new { bolt.Length, bolt.Diameter })
    .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

Si vous regardez la signature de la méthode Enumerable.ToDictionary , vous verrez que le premier argument est Func keySelector , dans votre cas, la TSource est de type anonyme et la TKey est une chaîne. Tout ce que vous avez à faire est de définir le mappage entre TSource et TKey et c'est exactement ce que la fonction bolt => $ "{bolt.Key.Length} _ {bolt.Key.Diameter} " fait.


0 commentaires

1
votes

Vous ne connaissez peut-être pas non plus cette solution, vous n'avez peut-être pas du tout besoin de formatage de chaîne. (vous pouvez utiliser C # 7 avec des tuples de valeur)

dic.TryGetValue((10, 20), out int count);

Et accéder comme

Dictionary<(int length, int diameter), int> boltFamilyList = selectedBolts
    .GroupBy(bolt => (bolt.Length, bolt.Diameter))
    .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

Où 10 et 20 sont la longueur et le diamètre p >


0 commentaires