¿Por qué ToLookup y GroupBy son diferentes?

111

.ToLookup<TSource, TKey>devuelve un ILookup<TKey, TSource>. ILookup<TKey, TSource>también implementa interfaz IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey>devuelve un IEnumerable<IGrouping<Tkey, TSource>>.

ILookup tiene la práctica propiedad de indexador, por lo que se puede usar como en un diccionario (o en una búsqueda), mientras que GroupBy no. GroupBy sin el indexador es una molestia para trabajar; Prácticamente, la única forma en que puede hacer referencia al objeto de retorno es recorriéndolo (o utilizando otro método de extensión LINQ). En otras palabras, en cualquier caso en que funcione GroupBy, ToLookup también funcionará.

Todo esto me deja con la pregunta de por qué me molestaría en usar GroupBy. ¿Por qué debería existir?

Shlomo
fuente
7
GroupByEs IQuerable, ILookupno es
Magnus
5
GroupBy no enumera la lista ToLookup la enumera de la misma manera ToList / ToArray
Aducci
3
Nominé esto para reabrir ya que la pregunta de la que supuestamente es un duplicado es sobre IGrouping en lugar de GroupBy e ILookup en lugar de ToLookup . Las diferencias entre esos son diferentes a las diferencias entre estos. Esto debería ser evidente por las diferencias en las respuestas entre las preguntas.
Sam
1
ambos crean un Lookup, pero lo GroupBycrean cuando el resultado se enumera reference.microsoft.com/#System.Core/System/Linq/…
Slai

Respuestas:

175

¿Por qué iba a molestarme con GroupBy? ¿Por qué debería existir?

¿Qué sucede cuando llama a ToLookup en un objeto que representa una tabla de base de datos remota con mil millones de filas?

Los mil millones de filas se envían a través del cable y usted crea la tabla de búsqueda localmente.

¿Qué sucede cuando llamas a GroupBy en un objeto de este tipo?

Se crea un objeto de consulta; fin de la historia.

Cuando se enumera ese objeto de consulta, el análisis de la tabla se realiza en el servidor de la base de datos y los resultados agrupados se envían de vuelta a pedido, unos pocos a la vez.

Lógicamente son lo mismo, pero las implicaciones de rendimiento de cada uno son completamente diferentes. Llamar a ToLookup significa que quiero un caché de todo ahora organizado por grupo . Llamar a GroupBy significa "Estoy construyendo un objeto para representar la pregunta '¿Cómo se verían estas cosas si las organizara por grupo?'"

Eric Lippert
fuente
6
El cartel no apunta específicamente a una IQueryable<T>representación. Su respuesta cubre esa situación, pero cuando es simple IEnumerable<T>(LINQ-to-Objects) puede parecer que no hay una razón para usar uno sobre el otro, que es a lo que creo que @Shlomo está tratando de llegar. No es el IQueryable<T>caso, sino el caso de LINQ-to-Objects.
casperOne
21
@casperOne: Creo que no entendiste mi punto. Incluso en el caso de LINQ-to-objects, llamar a GroupBy todavía no itera sobre la colección. (Como señaló Aducci en la respuesta que eliminó). Esa es una diferencia fundamental.
Eric Lippert
12
@EricLippert: Pero, ¿es solo un efecto secundario de la implementación o se garantiza que el enumerable se repetirá cuando llame a ToLookup, sin importar qué cambios se realicen en la implementación?
9
@Will: Tiene un punto excelente; la documentación no garantiza que ToLookup esté "ansioso". Probablemente debería tener en cuenta eso.
Eric Lippert
10
El entusiasmo lo explica. El lenguaje de 'ToMetaType' creo que implica entusiasmo; aunque obviamente se deja a la implementación. Los otros 'To's están ansiosos (ToList, ToArray, ToDictionary). Gracias chicos.
Shlomo
98

En palabras simples del mundo LINQ:

  • ToLookup() - ejecución inmediata
  • GroupBy() - ejecución diferida
sll
fuente
17

Los dos son similares, pero se utilizan en diferentes escenarios. .ToLookup()devuelve un objeto listo para usar que ya tiene todos los grupos (pero no el contenido del grupo) cargados con entusiasmo. Por otro lado, .GroupBy()devuelve una secuencia de grupos con carga diferida.

Los diferentes proveedores de LINQ pueden tener diferentes comportamientos para la carga impaciente y perezosa de los grupos. Con LINQ-to-Object probablemente hace poca diferencia, pero con LINQ-to-SQL (o LINQ-to-EF, etc.), la operación de agrupación se realiza en el servidor de la base de datos en lugar del cliente, por lo que es posible que desee para hacer un filtrado adicional en la clave de grupo (que genera una HAVINGcláusula) y luego solo obtener algunos de los grupos en lugar de todos. .ToLookup()no permitiría tal semántica ya que todos los elementos están ansiosamente agrupados.

Allon Guralnek
fuente