Birden Çok Sütuna Göre Grupla


967

LINQ'da GroupBy Birden Fazla Sütunu Nasıl Yapabilirim

SQL'de buna benzer bir şey:

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

Bunu LINQ'ya nasıl dönüştürebilirim:

QuantityBreakdown
(
    MaterialID int,
    ProductID int,
    Quantity float
)

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

Yanıtlar:


1212

Anonim bir tür kullanın.

Örneğin

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

29
Anonim türlerle gruplama konusunda yeniyseniz, bu örnekte 'yeni' anahtar kelimenin kullanımı sihir yapar.
Chris

8
nHibernate dll sorunları için hata alma ile mvc durumunda. GroupBy tarafından çözülen sorun (x => new {x.Column1, x.Column2}, (key, group) => new {Key1 = key.Column1, Key2 = key.Column2, Result = group.ToList ()});
Milan

Bu durumda yeni nesnelerin referans ile karşılaştırılacağını düşündüm, bu yüzden eşleşme yok - groupping yok.
HoGo

4
@HoGo anonim yazılan nesneleri, nesneleri eşitlerken kullanılan kendi Equals ve GetHashCode yöntemlerini uygular .
Byron Carasco

Linq'te yeni olduğunuzda çıktı veri yapısını görselleştirmek biraz zor. Bu, anonim türün anahtar olarak kullanıldığı bir gruplama oluşturur mu?
Jacques

760

Prosedür örneği

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

Nesne ne tür döndürülür?
mggSoft

5
@MGG_Soft Bu anonim bir tür olurdu
Alex

Bu kod benim için çalışmıyor: "Geçersiz anonim tür bildiricisi."
thalesfc

19
@Tom bu şekilde çalışmalı. Anonim tipteki C # alanlarını adlandırmayı atladığınızda, projeksiyondan en son erişilen özellik / alanın adını kullanmak istediğinizi varsayar. (Yani örneğiniz Mo0gles 'ile eşdeğerdir)
Chris Pfohl

1
cevabımı buldum. Ben Sütun1 ve Sütun2 özellikleri içeren yeni bir varlık (MyViewEntity) tanımlamak gerekir ve dönüş türü: IEnumerable <IGrouping <MyViewEntity, MyEntity >> ve Gruplama kod snip: MyEntityList.GroupBy (myEntity => yeni MyViewEntity {Column1 = myEntity. Sütun1, Sütun2 = myEntity.Column2});
Amir Chatrbahr

467

Tamam şu şekilde var:

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();

75
+1 - Kapsamlı örnek için teşekkürler. Diğer yanıtın parçacıkları çok kısa ve bağlamsız. Ayrıca bir toplama işlevi de gösterirsiniz (bu durumda Sum). Çok yararlı. Toplama işlevinin (yani MAX, MIN, SUM vb.) Kullanımını gruplandırmanın yan yana olduğunu ve ortak bir senaryo olduğunu düşünüyorum.
barrypicker

Burada: stackoverflow.com/questions/14189537/… , gruplama adı bilinen tek bir sütuna dayandığında bir veri tablosu için gösterilir, ancak gruplamanın yapılacağı sütunlar nasıl yapılırsa bu nasıl yapılabilir dinamik olarak oluşturulmalı mı?
bg

Bu, gruplama ve üzerinde toplama uygulama kavramını anlamada gerçekten yararlıdır.
rajibdotnet

1
Harika bir örnek ... tam aradığım şey. Düz-se bile benim ihtiyaçlarını çözmek için yeterli var lambda arıyordum bu mükemmel bir cevap oldu agrega gerekiyordu.
Kevbo

153

Birden Çok Sütuna Göre Grupla için bunu deneyin ...

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

Sütun3, Sütun4 vb. Ekleyebilirsiniz.


4
Bu çok yardımcı oldu ve çok daha fazla upvotes almalısınız! Resulttüm sütunlara bağlı tüm veri kümelerini içerir. Çok teşekkürler!
j00hi

1
not: ToList () yerine .AsEnumerable () kullanmak zorunda kaldım
GMan

1
Harika, bunun için teşekkürler. İşte benim örneğim. GetFees, bir IQueryable <Fee> RegistryAccountDA.GetFees (registerAccountId, fromDate, toDate) .GroupBy (x => yeni {x.AccountId, x.FeeName}, (anahtar, grup) => yeni {AccountId = key.AccountId , FeeName = key.FeeName, AppliedFee = group.Sum (x => x.AppliedFee) ?? 0M}). ToList ();
Craig B

Bu sorgudan gruplandırılmamış başka sütunlar almak mümkün müdür? Nesne dizisi varsa, bu nesneyi iki sütuna göre gruplandırmak istiyorum, ancak nesneden tüm özellikleri almak istiyorum, sadece bu iki sütunu değil.
FrenkyB


19

C # 7.1 veya üstü kullanılarak Tuplesve Inferred tuple element names(şu anda sadece çalışır linq to objectsve ifade ağaçları örneğin gerekli olduğunda o desteklenmez someIQueryable.GroupBy(...). Github sorunu ):

// 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 veya üstü kullanarak 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) });

18

Güçlü tür gruplama için bir Tuple <> da kullanabilirsiniz.

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),
}

4
Not: Linq To Entities'de yeni bir Tuple oluşturma desteklenmez
foolmoron

8

Bu soru grup özelliklerine göre sorulsa da, bir ADO nesnesine (DataTable gibi) göre birden çok sütuna göre gruplamak istiyorsanız, değişkenlere "yeni" öğelerinizi atamanız gerekir:

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);

1
Linq sorgusu "grup c yeni {c.Field <String> (" Başlık "), c.Field <String> (" CIF ")}" tarafından yapamadı ve bana çok zaman kazandın! son sorgu: "grup c tarafından yeni {titulo = c.Field <String> (" Title "), cif = c.Field <String> (" CIF ")}"
netadictos 15:18

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

7
Önceki yanıtlara hiçbir şey eklemez.
Mike Fuchs

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

İle birlikte Linq.Enumerable.Aggregate()bu daha dinamik bir özellikler sayısına göre gruplama sağlar: propertyValues.Aggregate((current, next) => current + " " + next).
Kai Hartmann

3
Bu, herkesin kredi verdiğinden daha iyi bir cevaptır. Sütun2'ye eklenen sütun1'in, sütun1'in farklı olduğu durumlar için aynı şeye eşit olacağı kombinasyon örnekleri olabilirse ("ab" "cde", "abc" "de" ile eşleşir) sorunlu olabilir. Bununla birlikte, dinamik bir tür kullanamıyorsanız bu harika bir çözümdür, çünkü gruptan sonra lambdasları ayrı ifadelerle önceden oluşturuyorsunuz.
Brandon Barkley

3
"ab" "cde" aslında "abc" "de" ile eşleşmemelidir, dolayısıyla aradaki boşluk.
Kai Hartmann

1
"abc de" "" ve "abc" "de" ne olacak?
AlbertK

@AlbertK işe yaramayacak sanırım.
Kai Hartmann


2

x'i yeni {x.Col, x.Col} 'a göre gruplandır


1

Dikkat edilmesi gereken bir şey, Lambda ifadeleri için bir nesne göndermeniz ve sınıf için bir örnek kullanamamanızdır.

Misal:

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

    public string Prop2 { get; set; }
}

Bu derlenecek, ancak döngü başına bir anahtar üretecektir .

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

Anahtar özellikleri adlandırmak ve sonra bunları almak istemiyorsanız, bunun yerine bunu yapabilirsiniz. Bu GroupBydoğru olacak ve size anahtar özellikler verecektir.

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;
}

0

For VB ve anonim / lambda :

query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.