LINQ Group By เป็นวัตถุพจนานุกรม


161

ฉันพยายามใช้ LINQ เพื่อสร้าง Dictionary<string, List<CustomObject>>List<CustomObject>จาก ฉันสามารถใช้งานได้โดยใช้ "var" แต่ฉันไม่ต้องการใช้ประเภทที่ไม่ระบุชื่อ นี่คือสิ่งที่ฉันมี

var x = (from CustomObject o in ListOfCustomObjects
      group o by o.PropertyName into t
      select t.ToList());

ฉันได้ลองใช้Cast<>()จากห้องสมุด LINQ เมื่อฉันมีxแต่ฉันได้รับปัญหาการรวบรวมผลของมันเป็นนักแสดงที่ไม่ถูกต้อง


จะทำอย่างไรถ้าคุณลอง var x = (จาก CustomObject o ใน ListOfCustomObjects กลุ่ม o โดย o.PropertyName เป็น t เลือก t) .ToList ();
esastincy

44
มีเหตุผลใดบ้างที่คุณต้องทำสิ่งนี้แทนที่จะใช้ ToLookup ซึ่งออกแบบมาสำหรับสิ่งนี้?
Jon Skeet

1
จอนคุณช่วยกรุณาโพสต์ตัวอย่างว่า ToLookup ทำงานอย่างไรในสถานการณ์นี้ ฉันไม่คุ้นเคยกับวิธี LINQ
Atari2600

8
@ JonSkeet คุณยอดเยี่ยมมาก! (ฉันหมายความว่าทุกคนรู้แล้ว แต่ก็ยัง) เหตุผลที่ฉันไม่ได้วางแผนที่จะใช้ ToLookup เป็นเพราะฉันไม่เคยได้ยินมาก่อนจนกระทั่งตอนนี้ ตอนนี้ฉันรู้!
neminem

1
เพื่อประโยชน์ของความสมบูรณ์การใช้varไม่ได้ใช้ประเภท "ไม่ระบุชื่อ" แต่ใช้ประเภท "นัย" new { thing = "stuff" };ประเภทความเป็นคลาสใหม่ที่สร้างขึ้นโดยคอมไพเลอร์ในการจัดการการก่อสร้าง ประเภทโดยนัยคือคลาสที่มีอยู่แล้วvarเป็นวิธีที่สะดวกในการอ้างอิงเมื่อตัวแปรถูกกำหนดทันทีประเภทตัวแปรสามารถอนุมานได้จากประเภทของวัตถุที่ได้รับมอบหมาย คุณสามารถพิมพ์ตัวแปรที่อ้างอิงถึงประเภทที่ไม่ระบุตัวตนโดยปริยายเช่น:var a = new { thing = "stuff" };
Michael Blackburn

คำตอบ:


351
Dictionary<string, List<CustomObject>> myDictionary = ListOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToDictionary(g => g.Key, g => g.ToList());

6
ยกเว้นว่าคุณต้องการคุณสมบัติจาก 'CustomObject' เป็นค่ารายการ (ไม่ได้แสดงในคำตอบนี้) มันก็คุ้มค่าที่จะตรวจสอบความคิดเห็นของเขาจอน Skeet กับคำถามที่แนะนำ ToLookup ()
ฌอน

3
นี่เป็นวิธีที่จะทำหากต้องการผลลัพธ์ที่ไม่เปลี่ยนรูปแบบ ToLookup ไม่เปลี่ยนรูป
Amit

1
2 Cents ของฉัน (เพียง 'เพราะมันทำให้ฉันดิ้นรนเป็นเวลาหนึ่งชั่วโมง :)): เมื่อจัดกลุ่มตามคุณสมบัติตรวจสอบให้แน่ใจว่าทรัพย์สินมีค่า! มิฉะนั้นวิธี Todict-method จะไม่สร้างคีย์ (สำหรับ String-Properties อย่างน้อย ... ) :)
dba

.GroupBy(o => o.PropertyName).ToDictionary(g => g.Key, g => g.ToList())นี่อาจเป็นส่วนหนึ่งของไลบรารีส่วนขยาย Linq ดังนั้นเราต้องทำเท่านั้น.ToDictionary(o=>o.PropertyName)
Jaider

3
@Jaider มีอยู่แล้วการทำงานดังกล่าวเพียงแค่เปลี่ยนด้วยToDictionary ToLookup
Robert Synoradzki

19

ฉันไม่สามารถแสดงความคิดเห็นใน @Michael Blackburn ได้ แต่ฉันเดาว่าคุณได้รับการโหวตเพราะ GroupBy ไม่จำเป็นในกรณีนี้

ใช้มันเหมือน:

var lookupOfCustomObjects = listOfCustomObjects.ToLookup(o=>o.PropertyName);
var listWithAllCustomObjectsWithPropertyName = lookupOfCustomObjects[propertyName]

นอกจากนี้ฉันได้เห็นวิธีนี้ทำได้ดีกว่าเมื่อใช้ GroupBy (). ToDictionary ()


ฉันกำลังทำการทับศัพท์ไม่ตอบคำถามด้วยวิธีที่ดีที่สุด
Michael Blackburn

1

สำหรับ @ atari2600 นี่คือคำตอบที่ดูเหมือนว่าใช้ ToLookup ในไวยากรณ์แลมบ์ดา:

var x = listOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToLookup(customObject => customObject);

โดยทั่วไปจะใช้การจัดกลุ่ม IGG และทำให้เป็นจริงสำหรับคุณในพจนานุกรมของรายการโดยมีค่าของ PropertyName เป็นกุญแจสำคัญ


ทำไมต้องลงคะแนน สิ่งนี้ไม่ถูกต้อง / ตอบคำถาม?
Michael Blackburn

1
ในกรณีที่คุณพลาด @RuudvK พูดถึงในคำตอบของเขาว่าเขาสงสัยว่ามีการโหวตเพราะ GroupBy ไม่จำเป็น ToLookupมีโอเวอร์โหลดที่จะทำให้งานเสร็จ
Jeff B

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

GroupBy (การโอเวอร์โหลดที่มีเพียงหนึ่งพารามิเตอร์) จะคืนค่า IEnumerable <IGrouping <TKey, TSource >> ต่อมา ToLookup จากนั้นเปลี่ยนเป็นรูปแบบที่ค่อนข้างซับซ้อนซึ่งไม่คล้ายกับ IDictionary <TKey, IList <TSource>> ToLookup ส่งคืนชนิดที่เหมาะสม
xtofs

-1

ต่อไปนี้ใช้งานได้สำหรับฉัน

var temp = ctx.Set<DbTable>()
  .GroupBy(g => new { g.id })
  .ToDictionary(d => d.Key.id);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.