Agrupar por varias columnas

¿Cómo puedo hacer GroupBy Multiple Columns en LINQ?

Algo similar a esto en SQL:

SELECT * FROM <TableName> GROUP BY <Column1>,<Column2>

¿Cómo puedo convertir esto a LINQ?

QuantityBreakdown
(
    MaterialID int,
    ProductID int,
    Quantity float
)

INSERT INTO @QuantityBreakdown (MaterialID, ProductID, Quantity)
SELECT MaterialID, ProductID, SUM(Quantity)
FROM @Transactions
GROUP BY MaterialID, ProductID

preguntado el 11 de mayo de 09 a las 04:05

14 Respuestas

Utilice un tipo anónimo.

Eg

group x by new { x.Column1, x.Column2 }

contestado el 11 de mayo de 09 a las 08:05

Si es nuevo en la agrupación con tipos anónimos, el uso de la palabra clave 'nueva' en este ejemplo hace la magia. - Chris

en caso de que mvc con nHibernate obtenga un error para problemas de dll. Problema resuelto por GroupBy (x => new {x.Column1, x.Column2}, (key, group) => new {Key1 = key.Column1, Key2 = key.Column2, Result = group.ToList ()}); - Milán

Pensé que en este caso los nuevos objetos se compararían por referencia, por lo que no hay coincidencia, no hay agrupación. - HoGo

Objetos escritos anónimos @HoGo implementar sus propios Equals y GetHashCode métodos que se utilizan al agrupar los objetos. - Byron Carasco

Es un poco difícil visualizar la estructura de datos de salida cuando eres nuevo en Linq. ¿Esto crea una agrupación donde se usa el tipo anónimo como clave? - Jacques

Muestra de procedimiento

.GroupBy(x => new { x.Column1, x.Column2 })

contestado el 08 de mayo de 12 a las 08:05

¿Qué tipo es el objeto devuelto? - mggsoft

@MGG_Soft que sería un tipo anónimo - Alex

Este código no me funciona: "Declarador de tipo anónimo no válido". - thalesfc

@Tom, esto debería funcionar como está. Cuando omite nombrar los campos de un tipo anónimo, C # asume que desea usar el nombre de la propiedad / campo finalmente accedido desde la proyección. (Entonces su ejemplo es equivalente a Mo0gles ') - chris pfohl

encontré mi respuesta. Necesito definir una nueva entidad (MyViewEntity) que contenga las propiedades Column1 y Column2 y el tipo de retorno es: IEnumerable > y el fragmento de código de agrupación es: MyEntityList.GroupBy (myEntity => new MyViewEntity {Column1 = myEntity.Column1, Column2 = myEntity.Column2}); - Amir Chatrbahr

Ok tengo esto como:

var query = (from t in Transactions
             group t by new {t.MaterialID, t.ProductID}
             into grp
                    select new
                    {
                        grp.Key.MaterialID,
                        grp.Key.ProductID,
                        Quantity = grp.Sum(t => t.Quantity)
                    }).ToList();

Respondido el 05 de Septiembre de 11 a las 15:09

+1 - Gracias por el ejemplo completo. Los fragmentos de la otra respuesta son demasiado cortos y sin contexto. También muestra una función agregada (Suma en este caso). Muy útil. Considero que el uso de una función agregada (es decir, MAX, MIN, SUM, etc.) junto con la agrupación es un escenario común. - recogedor de barry

Aquí : stackoverflow.com/questions/14189537/… , se muestra para una tabla de datos cuando la agrupación se basa en una sola columna, cuyo nombre se conoce, pero ¿cómo se puede hacer si las columnas a partir de las cuales se va a realizar la agrupación tienen que generarse dinámicamente? - bg

Esto es realmente útil para comprender el concepto de agrupación y aplicar agregación sobre él. - rajibdotnet

Gran ejemplo ... justo lo que estaba buscando. Incluso necesitaba el agregado, por lo que esta fue la respuesta perfecta, aunque estaba buscando lambda, obtuve suficiente para resolver mis necesidades. - Kevbo

teniendo grp.Key. era lo que necesitaba para que funcionara, ¡gracias! - rob23

Para agrupar por varias columnas, intente esto en su lugar ...

GroupBy(x=> new { x.Column1, x.Column2 }, (key, group) => new 
{ 
  Key1 = key.Column1,
  Key2 = key.Column2,
  Result = group.ToList() 
});

De la misma manera puede agregar Column3, Column4, etc.

Respondido el 30 de diciembre de 15 a las 18:12

¡Eso fue muy útil y debería obtener muchos más votos a favor! Result contiene todos los conjuntos de datos vinculados a todas las columnas. ¡Muchas gracias! - j00hola

nota: tuve que usar .AsEnumerable () en lugar de ToList () - GMan

Impresionante, gracias por esto. Este es mi ejemplo. Tenga en cuenta que GetFees devuelve un IQueryable RegistryAccountDA.GetFees (registryAccountId, fromDate, toDate) .GroupBy (x => new {x.AccountId, x.FeeName}, (key, group) => new {AccountId = key.AccountId, FeeName = key.FeeName, AppliedFee = group.Sum (x => x.AppliedFee) ?? 0M}). ToList (); - Craig B

¿Es posible obtener otras columnas de esta consulta que no estén agrupadas? Si hay una matriz de objeto, me gustaría obtener este objeto agrupado por dos columnas, pero obtener todas las propiedades del objeto, no solo esas dos columnas. - FrenkyB

Desde C # 7 también puede usar tuplas de valor:

group x by (x.Column1, x.Column2)

or

.GroupBy(x => (x.Column1, x.Column2))

respondido 01 nov., 17:15

Bueno, creo que te falta un extra) al final. No está cerrando el () - StuiterSlurf

Lo he agregado. - Nathan Tregillus

.GroupBy (x => new {x.Column1, x.Column2}) - Zahidul Islam Jamy

C # 7.1 o superior usar Tuples y Inferred tuple element names (actualmente solo funciona con linq to objects y no es compatible cuando se requieren árboles de expresión, por ejemplo someIQueryable.GroupBy(...). Problema de Github):

// declarative query syntax
var result = 
    from x in inMemoryTable
    group x by (x.Column1, x.Column2) into g
    select (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity));

// or method syntax
var result2 = inMemoryTable.GroupBy(x => (x.Column1, x.Column2))
    .Select(g => (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity)));

C # 3 o superior usar anonymous types:

// declarative query syntax
var result3 = 
    from x in table
    group x by new { x.Column1, x.Column2 } into g
    select new { g.Key.Column1, g.Key.Column2, QuantitySum = g.Sum(x => x.Quantity) };

// or method syntax
var result4 = table.GroupBy(x => new { x.Column1, x.Column2 })
    .Select(g => 
      new { g.Key.Column1, g.Key.Column2 , QuantitySum= g.Sum(x => x.Quantity) });

Respondido el 28 de diciembre de 19 a las 12:12

Wow gracias. Esto ha dejado una huella en el cerebro y ha aumentado la capacidad de posibilidades. - Barry

Súper ----- :) :) - Tulasiram

También puede utilizar una Tupla <> para una agrupación fuertemente tipada.

from grouping in list.GroupBy(x => new Tuple<string,string,string>(x.Person.LastName,x.Person.FirstName,x.Person.MiddleName))
select new SummaryItem
{
    LastName = grouping.Key.Item1,
    FirstName = grouping.Key.Item2,
    MiddleName = grouping.Key.Item3,
    DayCount = grouping.Count(), 
    AmountBilled = grouping.Sum(x => x.Rate),
}

Respondido el 29 de diciembre de 15 a las 20:12

Nota: No se admite la creación de una nueva tupla en Linq To Entities - tonto

Aunque esta pregunta se refiere a las propiedades de grupo por clase, si desea agrupar por varias columnas contra un objeto ADO (como un DataTable), debe asignar sus elementos "nuevos" a las variables:

EnumerableRowCollection<DataRow> ClientProfiles = CurrentProfiles.AsEnumerable()
                        .Where(x => CheckProfileTypes.Contains(x.Field<object>(ProfileTypeField).ToString()));
// do other stuff, then check for dups...
                    var Dups = ClientProfiles.AsParallel()
                        .GroupBy(x => new { InterfaceID = x.Field<object>(InterfaceField).ToString(), ProfileType = x.Field<object>(ProfileTypeField).ToString() })
                        .Where(z => z.Count() > 1)
                        .Select(z => z);

Respondido el 17 de enero de 18 a las 18:01

No pude hacer la consulta Linq "grupo c por nuevo {c. Campo ("Título"), c. Campo ("CIF")} ", y me ahorraste mucho tiempo !! la consulta final fue:" grupo c por nuevo {titulo = c.Field ("Título"), cif = c. Campo ("CIF")} "- netadictos

var Results= query.GroupBy(f => new { /* add members here */  });

Respondido el 30 de diciembre de 16 a las 10:12

No agrega nada a las respuestas anteriores. - mike fuchs

.GroupBy(x => (x.MaterialID, x.ProductID))

Respondido el 27 de diciembre de 17 a las 11:12

Considere agregar una explicación sobre cómo este código resuelve el problema. - Rosário Pereira Fernandes

.GroupBy(x => x.Column1 + " " + x.Column2)

contestado el 19 de mayo de 17 a las 07:05

Combinado con Linq.Enumerable.Aggregate() esto incluso permite agrupar por un número dinámico de propiedades: propertyValues.Aggregate((current, next) => current + " " + next). - kai hartmann

Esta es una mejor respuesta de la que nadie cree. Puede ser problemático si pudiera haber casos de combinaciones donde la columna1 agregada a la columna2 equivaldría a lo mismo para situaciones en las que la columna1 es diferente ("ab" "cde" coincidiría con "abc" "de"). Dicho esto, esta es una gran solución si no puede usar un tipo dinámico porque está preconstruyendo lambdas después del grupo en expresiones separadas. - brandon barkley

"ab" "cde" en realidad no debería coincidir con "abc" "de", de ahí el espacio en blanco en el medio. - kai hartmann

¿qué pasa con "abc de" "" y "abc" "de"? - AlbertoK

@AlbertK Me temo que eso no funcionaría. - kai hartmann

agrupar x por nuevo {x.Col, x.Col}

Respondido 23 Oct 17, 16:10

Una cosa a tener en cuenta es que debe enviar un objeto para las expresiones Lambda y no puede usar una instancia para una clase.

Ejemplo:

public class Key
{
    public string Prop1 { get; set; }

    public string Prop2 { get; set; }
}

Esto se compilará pero generará una llave por ciclo.

var groupedCycles = cycles.GroupBy(x => new Key
{ 
  Prop1 = x.Column1, 
  Prop2 = x.Column2 
})

Si no desea nombrar las propiedades clave y luego recuperarlas, puede hacerlo así. Esta voluntad GroupBy correctamente y darle las propiedades clave.

var groupedCycles = cycles.GroupBy(x => new 
{ 
  Prop1 = x.Column1, 
  Prop2= x.Column2 
})

foreach (var groupedCycle in groupedCycles)
{
    var key = new Key();
    key.Prop1 = groupedCycle.Key.Prop1;
    key.Prop2 = groupedCycle.Key.Prop2;
}

Respondido 26 Abr '18, 21:04

Para VB y anónimo / lambda:

query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })

contestado el 06 de mayo de 20 a las 13:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.