LINQ Group By dans un objet Dictionary

161

J'essaie d'utiliser LINQ pour créer un fichier à Dictionary<string, List<CustomObject>>partir d'un fichier List<CustomObject>. Je peux faire fonctionner cela en utilisant "var", mais je ne veux pas utiliser de types anonymes. Voici ce que j'ai

var x = (from CustomObject o in ListOfCustomObjects
      group o by o.PropertyName into t
      select t.ToList());

J'ai également essayé d'utiliser à Cast<>()partir de la bibliothèque LINQ une fois que je l'ai fait x, mais j'ai des problèmes de compilation en raison du fait qu'il s'agit d'un cast invalide.

Atari2600
la source
Que faire si vous essayez var x = (de CustomObject o dans le groupe ListOfCustomObjects o par o.PropertyName dans t select t) .ToList ();
esastincy
44
Y a-t-il une raison pour laquelle vous devez faire cela plutôt que d'utiliser ToLookup, qui est conçu pour cela?
Jon Skeet
1
Jon, pourriez-vous s'il vous plaît poster un exemple de la façon dont ToLookup fonctionne dans cette situation? Je ne connais pas cette méthode LINQ.
Atari2600
8
@JonSkeet Vous êtes génial! (Je veux dire, tout le monde le savait déjà, mais quand même.) La raison pour laquelle je n'avais pas l'intention d'utiliser ToLookup était parce que je n'en avais jamais entendu parler jusqu'à présent. Maintenant je sais!
neminem
1
Juste pour être complet, utiliser n'utilise varpas un type "anonyme", il utilise un type "implicite". Les types anonymes sont de nouvelles classes créées par le compilateur pour gérer la construction new { thing = "stuff" };. Les types implicites sont des classes existantes, varc'est juste un moyen pratique de les référencer lorsque la variable est assignée immédiatement, le type de variable peut être déduit du type de l'objet qui lui est assigné. Vous pouvez même taper implicitement une variable référençant un type anonyme, à savoir:var a = new { thing = "stuff" };
Michael Blackburn

Réponses:

351
Dictionary<string, List<CustomObject>> myDictionary = ListOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToDictionary(g => g.Key, g => g.ToList());
Yuriy Faktorovich
la source
6
À moins que vous n'ayez besoin d'une propriété de 'CustomObject' comme valeur de liste (non affichée dans cette réponse), il vaut la peine de vérifier son codeliness Le commentaire de Jon Skeet à la question recommandant ToLookup ().
Shaun
3
c'est la manière de le faire si un résultat non immuable est souhaité. ToLookup est immuable.
Amit
1
Mes 2 cents (juste parce que cela m'a fait lutter pendant une heure :)): lors du regroupement par propriété, assurez-vous que la propriété a une valeur! Sinon, la méthode Todict échoue à générer la clé (pour String-Properties au moins ...) :)
dba
.GroupBy(o => o.PropertyName).ToDictionary(g => g.Key, g => g.ToList())Cela pourrait faire partie de la bibliothèque d'extension Linq. donc nous n'avons qu'à faire.ToDictionary(o=>o.PropertyName)
Jaider
3
@Jaider, il existe déjà une telle fonctionnalité: il suffit de remplacer ToDictionarypar ToLookup.
Robert Synoradzki
19

Je ne peux pas faire de commentaire sur @Michael Blackburn, mais je suppose que vous avez obtenu le vote négatif car le GroupBy n'est pas nécessaire dans ce cas.

Utilisez-le comme:

var lookupOfCustomObjects = listOfCustomObjects.ToLookup(o=>o.PropertyName);
var listWithAllCustomObjectsWithPropertyName = lookupOfCustomObjects[propertyName]

De plus, j'ai vu cela mieux fonctionner que lors de l'utilisation de GroupBy (). ToDictionary ().

RuudvK
la source
J'effectuais une translittération, ne répondant pas à la question de la meilleure manière possible.
Michael Blackburn
1

Pour @ atari2600, voici à quoi ressemblerait la réponse en utilisant ToLookup dans la syntaxe lambda:

var x = listOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToLookup(customObject => customObject);

Fondamentalement, il prend l'IGrouping et le matérialise pour vous dans un dictionnaire de listes, avec les valeurs de PropertyName comme clé.

Michael Blackburn
la source
Pourquoi un vote négatif? N'est-ce pas exact / ne répond pas à la question?
Michael Blackburn
1
Au cas où vous l'auriez manqué, @RuudvK a mentionné dans sa réponse qu'il soupçonnait que le vote défavorable était dû au fait que GroupBy n'était pas nécessaire. ToLookupa une surcharge qui fera le travail.
Jeff B
J'ai manqué cette réponse, merci de m'avoir taguée. Cela a du sens, le regroupement est syntaxiquement inutile, je ne le laissais que pour rendre la transition de la syntaxe de requête à la syntaxe de méthode plus claire.
Michael Blackburn
GroupBy (la surcharge avec un seul paramètre) renvoie un IEnumerable <IGrouping <TKey, TSource >> le ToLookup suivant le transforme ensuite en un type assez compliqué qui n'est même pas similaire à un IDictionary <TKey, IList <TSource>> juste le ToLookup renvoie le type approprié.
xtofs
-1

Ce qui suit a fonctionné pour moi.

var temp = ctx.Set<DbTable>()
  .GroupBy(g => new { g.id })
  .ToDictionary(d => d.Key.id);
Leo Barbas
la source