LINQ Group By en un objeto de diccionario

161

Estoy tratando de usar LINQ para crear un Dictionary<string, List<CustomObject>>de a List<CustomObject>. Puedo hacer que esto funcione usando "var", pero no quiero usar tipos anónimos. Esto es lo que tengo

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

También intenté usarlo Cast<>()desde la biblioteca LINQ una vez que lo hice x, pero tengo problemas de compilación en el sentido de que es un molde inválido.

Atari2600
fuente
¿Qué sucede si prueba var x = (desde CustomObject o en el grupo ListOfCustomObjects o por o.PropertyName en t select t) .ToList ();
esastincy
44
¿Hay alguna razón por la que necesite hacer esto en lugar de usar ToLookup, que está diseñado para esto?
Jon Skeet
1
Jon, ¿podrías publicar un ejemplo de cómo funciona ToLookup en esta situación? No estoy familiarizado con ese método LINQ.
Atari2600
8
@ JonSkeet ¡Eres increíble! (Quiero decir, todos ya lo sabían, pero aún así). La razón por la que no estaba planeando usar ToLookup fue porque nunca había oído hablar de eso hasta ahora. ¡Ahora sé!
neminem
1
Solo por completar, usar varno es usar un tipo "anónimo", es usar un tipo "implícito". Los tipos anónimos son nuevas clases creadas por el compilador para manejar la construcción new { thing = "stuff" };. Los tipos implícitos son clases existentes, vares solo una forma conveniente de referenciarlos cuando la variable se asigna de inmediato, el tipo de variable se puede inferir del tipo del objeto que se le asigna. Incluso puede escribir implícitamente una variable que hace referencia a un tipo anónimo, es decir:var a = new { thing = "stuff" };
Michael Blackburn

Respuestas:

350
Dictionary<string, List<CustomObject>> myDictionary = ListOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToDictionary(g => g.Key, g => g.ToList());
Yuriy Faktorovich
fuente
66
A menos que necesite una propiedad de 'CustomObject' como valor de la lista (no se muestra en esta respuesta), vale la pena verificar su codicia el comentario de Jon Skeet a la pregunta que recomienda ToLookup ().
Shaun
3
esta es la forma de hacerlo si se desea un resultado no inmutable. ToLookup es inmutable.
Amit
1
Mis 2 centavos (solo porque me mantuvo luchando durante una hora :)): al agrupar por una propiedad, ¡asegúrese de que la propiedad tenga un valor! De lo contrario, el método Todict falla al generar la clave (para String-Properties al menos ...) :)
dba
.GroupBy(o => o.PropertyName).ToDictionary(g => g.Key, g => g.ToList())Esto podría ser parte de la biblioteca de extensión Linq. así que solo tenemos que hacerlo.ToDictionary(o=>o.PropertyName)
Jaider
3
@Jaider, ya existe tal funcionalidad: simplemente reemplace ToDictionarycon ToLookup.
Robert Synoradzki
19

No puedo comentar sobre @Michael Blackburn, pero supongo que recibió el voto negativo porque GroupBy no es necesario en este caso.

Úselo como:

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

Además, he visto que esto funciona mucho mejor que cuando se usa GroupBy (). ToDictionary ().

RuudvK
fuente
Estaba realizando una transliteración, sin responder a la pregunta de la mejor manera posible.
Michael Blackburn
1

Para @ atari2600, así es como se vería la respuesta usando ToLookup en la sintaxis lambda:

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

Básicamente, toma el IGrouping y lo materializa en un diccionario de listas, con los valores de PropertyName como clave.

Michael Blackburn
fuente
¿Por qué un voto negativo? ¿No es esto correcto / responder la pregunta?
Michael Blackburn
1
En caso de que te lo hayas perdido, @RuudvK mencionó en su respuesta que sospecha que el voto negativo se debe a que GroupBy es innecesario. ToLookuptiene una sobrecarga que hará el trabajo.
Jeff B
Extrañé esa respuesta, gracias por etiquetarme. Tiene sentido, la Agrupación es sintácticamente innecesaria, solo la estaba dejando para que la transición de la sintaxis de consulta a la sintaxis del método sea más clara.
Michael Blackburn
GroupBy (la sobrecarga con un solo parámetro) devuelve un IEnumerable <IGrouping <TKey, TSource >> el ToLookup posterior y luego lo convierte en un tipo bastante complicado que ni siquiera es similar a un IDictionary <TKey, IList <TSource>> solo el ToLookup devuelve el tipo apropiado.
xtofs
-1

Lo siguiente funcionó para mí.

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