LINQ กับ groupby และนับ


222

นี่เป็นเรื่องง่าย แต่ฉันกำลังแพ้: ให้ชุดข้อมูลประเภทนี้:

UserInfo(name, metric, day, other_metric)

และชุดข้อมูลตัวอย่างนี้:

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

ฉันต้องการดึงข้อมูลตารางที่แสดงรายการตัวชี้วัดตามลำดับ (0,1,2,3 .. ) โดยมีจำนวนครั้งทั้งหมดที่การนับเกิดขึ้น ดังนั้นจากชุดนี้คุณจะได้:

0 3    
1 2    
2 2    
3 1

ฉันกำลังต่อสู้กับไวยากรณ์ของ LINQ แต่ฉันติดอยู่ที่ที่จะวางกลุ่มโดยนับและช่วย .... ใด ๆ ??

โพสต์แก้ไข: ฉันไม่สามารถรับคำตอบที่โพสต์เพื่อให้ทำงานได้เนื่องจากพวกเขาส่งคืนหนึ่งระเบียนด้วยจำนวนการนับที่แตกต่างกันเสมอ อย่างไรก็ตามฉันสามารถรวบรวมตัวอย่าง LINQ ไปยัง SQL ที่ทำงาน:

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

ผลลัพธ์นี้ทำให้ฉันมีชุดของระเบียนที่สั่งด้วย 'ตัวชี้วัด' และจำนวนผู้ใช้ที่เชื่อมโยงกับแต่ละรายการ ฉันค่อนข้างใหม่กับ LINQ โดยทั่วไปและสำหรับสายตาที่ไม่ได้รับการฝึกฝนวิธีการนี้ดูเหมือนว่าคล้ายคลึงกับวิธี LINQ บริสุทธิ์มาก แต่ก็ให้คำตอบที่ต่างออกไป


ใช่ฉันมี แต่คำอธิบายของจิมมี่ช่วยฉันได้มากกว่านี้ อย่างไรก็ตามฉันไม่สามารถยกตัวอย่างงานของเขาได้ แต่มันทำให้ฉันไปในทิศทางใหม่
Gio

@Jimmy ใช้ไวยากรณ์การทำงานสำหรับนิพจน์ LINQ แทนที่จะใช้ไวยากรณ์คิวรี LINQ มาตรฐานและเขาตัดสินใจที่จะแสดงการดำเนินการทันทีของฟังก์ชันเหล่านั้นมากกว่ารูปแบบการดำเนินการล่าช้า สำหรับคนใหม่ที่จะเกิดความสับสน ไม่รู้ว่าทำไมเขาทำอย่างนั้น
Richard Robertson

คำตอบ:


396

หลังจากการโทรGroupByคุณจะได้รับชุดของกลุ่มIEnumerable<Grouping>ที่การจัดกลุ่มแต่ละตัวแสดงให้เห็นถึงการKeyใช้ในการสร้างกลุ่มและยังเป็นIEnumerable<T>รายการใด ๆ ที่อยู่ในชุดข้อมูลเดิมของคุณ คุณเพียงแค่เรียกการCount()จัดกลุ่มนั้นเพื่อให้ได้ผลรวมย่อย

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


นี่เป็นการตอบกลับอย่างรวดเร็วที่ยอดเยี่ยม แต่ฉันมีปัญหาเล็กน้อยกับบรรทัดแรกโดยเฉพาะ "data.groupby (info => info.metric)"

ฉันสมมติว่าคุณมีรายการ / อาร์เรย์ของบางอย่างclassที่ดูเหมือน

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

เมื่อคุณทำเช่นdata.GroupBy(x => x.metric)นั้นมันหมายถึง "สำหรับแต่ละองค์ประกอบxใน IEnumerable ที่กำหนดโดยdataคำนวณมัน.metricจากนั้นจัดกลุ่มองค์ประกอบทั้งหมดที่มีตัวชี้วัดที่เหมือนกันลงใน a Groupingและส่งคืนIEnumerableกลุ่มผลลัพธ์ทั้งหมดของกลุ่ม

    <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

มันจะส่งผลให้ผลลัพธ์ต่อไปนี้หลังจาก groupby:

(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]

นี่เป็นการตอบกลับอย่างรวดเร็วที่ยอดเยี่ยม แต่ฉันมีปัญหาเล็กน้อยกับบรรทัดแรกโดยเฉพาะ "data.groupby (info => info.metric)" โดยชัดแจ้ง 'data' เป็นชุดข้อมูลในปัจจุบัน แต่ชุดข้อมูล 'info.metric' ซ้ำกัน คำจำกัดความของคลาส?
Gio

"info.metric" จะเป็นคุณสมบัติ / เขตข้อมูลในคลาส UserInfo ที่คุณพูดถึงในคำถามของคุณ
lee-m

1
ขอบคุณที่ทราบว่าจริง ๆ แล้วสิ่งนี้ดูเหมือนจะให้ค่าเดียวกับฉัน - นั่นคือจำนวนรวมของการนับที่แตกต่างกัน ในตัวอย่างนี้ฉันได้รับ "ตัวชี้วัด 4" ซึ่งบ่งบอกถึงจำนวนที่แตกต่างกันที่ฉันมี
Gio

1
ว้าว. คุณอธิบายการจัดกลุ่มทั้งหมด !! เพียงอย่างเดียวนั่นก็คุ้มค่ากับการโพสต์ .... ฉันยังได้รับผลการวัด "4" แต่ขอบคุณ!
Gio

4
จุดเริ่มต้นของคำตอบนี้ "หลังจากโทร GroupBy คุณจะได้รับกลุ่มของ IEnumerable <Grouping> โดยที่การจัดกลุ่มแต่ละครั้งจะเปิดเผยคีย์ที่ใช้ในการสร้างกลุ่มและยังเป็น IEnumerable <T> ของรายการใด ๆ ที่อยู่ในข้อมูลต้นฉบับของคุณ set "เป็นคำอธิบายที่ชัดเจนที่สุดของ LINQ Group โดยที่ฉันได้อ่านแล้วขอบคุณ
dumbledad

48

สมมติว่าuserInfoListเป็นList<UserInfo>:

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

ฟังก์ชั่นแลมบ์ดาสำหรับGroupBy(), n => n.metricหมายความว่ามันจะได้รับข้อมูลmetricจากทุกUserInfoวัตถุที่พบ ประเภทของnขึ้นอยู่กับบริบทในการเกิดขึ้นครั้งแรกของประเภทUserInfoเพราะรายการมีUserInfoวัตถุ ในการเกิดขึ้นที่สองnคือประเภทGroupingเพราะตอนนี้มันเป็นรายการของGroupingวัตถุ

Groupings มีวิธีการขยายเช่น.Count(), .Key()และสวยอะไรอย่างอื่นที่คุณคาดหวัง เช่นเดียวกับที่คุณจะตรวจสอบ.Lenghtในstringคุณสามารถตรวจสอบ.Count()ในกลุ่ม


23
userInfos.GroupBy(userInfo => userInfo.metric)
        .OrderBy(group => group.Key)
        .Select(group => Tuple.Create(group.Key, group.Count()));

1
พิมพ์ผิดขนาดเล็ก -> group.keyใน Select (... ) ต้องเป็นgroup.Key
Jan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.