LINQ dengan groupby dan hitung

221

Ini cukup sederhana tapi saya bingung: Mengingat tipe data ini:

UserInfo(name, metric, day, other_metric)

dan kumpulan data sampel ini:

joe  1 01/01/2011 5
jane 0 01/02/2011 9
john 2 01/03/2011 0
jim  3 01/04/2011 1
jean 1 01/05/2011 3
jill 2 01/06/2011 5
jeb  0 01/07/2011 3
jenn 0 01/08/2011 7

Saya ingin mengambil tabel yang mencantumkan metrik secara berurutan (0,1,2,3 ..) dengan jumlah total kali penghitungan terjadi. Jadi dari set ini Anda akan berakhir dengan:

0 3    
1 2    
2 2    
3 1

Saya bergulat dengan sintaks LINQ tetapi saya terjebak di mana harus meletakkan groupby dan menghitung .... ada bantuan ??

Edit POST: Saya tidak pernah bisa mendapatkan jawaban yang diposting untuk bekerja karena mereka selalu mengembalikan satu catatan dengan jumlah hitungan yang berbeda. Namun saya bisa mengumpulkan contoh LINQ to SQL yang berhasil:

        var pl = from r in info
                 orderby r.metric    
                 group r by r.metric into grp
                 select new { key = grp.Key, cnt = grp.Count()};

Hasil ini memberi saya satu set catatan terurut dengan 'metrik' dan jumlah pengguna yang terkait dengan masing-masing. Saya jelas baru di LINQ secara umum dan di mata saya yang tidak terlatih, pendekatan ini tampaknya sangat mirip dengan pendekatan LINQ murni namun memberi saya jawaban yang berbeda.

Gio
sumber
Ya saya pernah, tetapi penjelasan jimmy membantu saya lebih dari itu. Namun saya tidak pernah bisa mendapatkan teladannya untuk bekerja tetapi itu membawa saya ke arah yang baru.
Gio
@Jimmy menggunakan sintaks fungsional untuk ekspresi LINQ daripada sintaks query LINQ standar, ditambah dia memutuskan untuk menunjukkan eksekusi langsung dari fungsi-fungsi itu daripada format eksekusi yang tertunda. Untuk orang baru itu akan membingungkan. Tidak tahu mengapa dia melakukan itu.
Richard Robertson

Jawaban:

395

Setelah menelepon GroupBy, Anda mendapatkan serangkaian grup IEnumerable<Grouping>, di mana masing-masing Pengelompokan itu sendiri memperlihatkan yang Keydigunakan untuk membuat grup dan juga merupakan IEnumerable<T>item apa pun yang ada dalam kumpulan data asli Anda. Anda hanya perlu memanggil Count()Pengelompokan itu untuk mendapatkan subtotal.

foreach(var line in data.GroupBy(info => info.metric)
                        .Select(group => new { 
                             Metric = group.Key, 
                             Count = group.Count() 
                        })
                        .OrderBy(x => x.Metric)
{
     Console.WriteLine("{0} {1}", line.Metric, line.Count);
}


Ini adalah balasan yang sangat cepat tetapi saya mengalami sedikit masalah dengan baris pertama, khususnya "data.groupby (info => info.metric)"

Saya berasumsi Anda sudah memiliki daftar / array beberapa classyang terlihat seperti

class UserInfo {
    string name;
    int metric;
    ..etc..
} 
...
List<UserInfo> data = ..... ;

Ketika Anda melakukannya data.GroupBy(x => x.metric), itu berarti "untuk setiap elemen xdalam IEnumerable yang ditentukan oleh data, hitung .metric, lalu kelompokkan semua elemen dengan metrik yang sama ke dalam Groupingdan kembalikan IEnumerablesemua grup yang dihasilkan. Diberikan contoh kumpulan data Anda dari

    <DATA>           | Grouping Key (x=>x.metric) |
joe  1 01/01/2011 5  | 1
jane 0 01/02/2011 9  | 0
john 2 01/03/2011 0  | 2
jim  3 01/04/2011 1  | 3
jean 1 01/05/2011 3  | 1
jill 2 01/06/2011 5  | 2
jeb  0 01/07/2011 3  | 0
jenn 0 01/08/2011 7  | 0

itu akan menghasilkan hasil berikut setelah grup oleh:

(Group 1): [joe  1 01/01/2011 5, jean 1 01/05/2011 3]
(Group 0): [jane 0 01/02/2011 9, jeb  0 01/07/2011 3, jenn 0 01/08/2011 7]
(Group 2): [john 2 01/03/2011 0, jill 2 01/06/2011 5]
(Group 3): [jim  3 01/04/2011 1]
Jimmy
sumber
Ini adalah jawaban yang sangat cepat tetapi saya mengalami sedikit masalah dengan baris pertama, khususnya "data.groupby (info => info.metric)". Jelas 'data' adalah kumpulan data saat ini tetapi apa yang dimaksud dengan representet 'info.metric'? definisi kelas?
Gio
"info.metric" akan menjadi properti metrik / bidang pada kelas UserInfo yang Anda sebutkan dalam pertanyaan Anda.
lee-m
1
Terima kasih mengetahuinya tetapi sebenarnya ini tampaknya memberi saya nilai tunggal - yaitu jumlah total jumlah metrik yang berbeda. Dalam contoh ini saya mendapatkan "metrik 4" yang menunjukkan kepada saya berapa banyak jumlah berbeda yang saya miliki.
Gio
1
Wow. Anda benar-benar menjelaskan pengelompokan !! Itu saja layak posting .... saya masih mendapatkan hasil "metrik 4" tapi terima kasih!
Gio
4
Awal dari jawaban ini, "setelah memanggil GroupBy, Anda mendapatkan serangkaian grup IEnumerable <Grouping>, di mana masing-masing Grouping memperlihatkan kunci yang digunakan untuk membuat grup dan juga merupakan <T> IEnumerable item apa pun yang ada dalam data asli Anda set ", adalah penjelasan paling jelas dari LINQ Group. Saya belum pernah membaca, terima kasih.
Dumbledad
48

Dengan asumsi userInfoListadalah List<UserInfo>:

        var groups = userInfoList
            .GroupBy(n => n.metric)
            .Select(n => new
            {
                MetricName = n.Key,
                MetricCount = n.Count()
            }
            )
            .OrderBy(n => n.MetricName);

Fungsi lambda untuk GroupBy(), n => n.metricberarti akan mendapatkan bidang metricdari setiap UserInfoobjek yang ditemui. Jenis ntergantung pada konteksnya, pada kejadian pertama jenisnya UserInfo, karena daftar berisi UserInfoobjek. Pada kejadian kedua nadalah tipe Grouping, karena sekarang daftar Groupingobjek.

GroupingAda metode ekstensi seperti .Count(), .Key()dan cukup banyak hal lain yang Anda harapkan. Sama seperti Anda akan memeriksa .Lenghtpada string, Anda dapat memeriksa .Count()grup.

Vladislav Zorov
sumber
23
userInfos.GroupBy(userInfo => userInfo.metric)
        .OrderBy(group => group.Key)
        .Select(group => Tuple.Create(group.Key, group.Count()));
DanielOfTaebl
sumber
1
kesalahan ketik kecil -> group.keydalam Pilih (...) harusgroup.Key
Jan