ความแตกต่างใน Linq ขึ้นอยู่กับเพียงหนึ่งฟิลด์ของตาราง


133

ฉันกำลังพยายามใช้ .distinct ใน Linq เพื่อให้ได้ผลลัพธ์ตามฟิลด์หนึ่งของตาราง (ดังนั้นไม่จำเป็นต้องมีระเบียนที่ซ้ำกันทั้งหมดจากตาราง)

ฉันรู้ว่าการเขียนแบบสอบถามพื้นฐานโดยใช้ความแตกต่างดังต่อไปนี้:

var query = (from r in table1
orderby r.Text
select r).distinct();

แต่ฉันต้องการผลลัพธ์ที่r.textไม่ซ้ำกัน


คุณต้องระบุเขตข้อมูลที่คุณต้องการให้แตกต่างกันดูmsdn.microsoft.com/en-us/library/bb348436.aspx
Antarr Byrd

คำตอบ:


300

ลองสิ่งนี้:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

สิ่งนี้จะจัดกลุ่มตารางตามTextและใช้แถวแรกจากแต่ละกลุ่มส่งผลให้แถวTextแตกต่างกัน


2
เกิดอะไรขึ้นถ้า groupby มีมากกว่า 1 สนาม?

6
@ user585440: ในกรณีนี้คุณใช้ประเภทที่ไม่ระบุชื่อเช่น:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth

2
ใช่คุณพูดถูกและฉันพบแล้ว ขอบคุณอยู่ดี และฉันก็พบว่าการเลือก (x => x.First ()) อาจทำให้เกิดปัญหาได้ มันจะดีกว่าที่จะเปลี่ยนเป็นเลือก (x => x.FirstOrDefault ());

6
ฉันต้องใช้ FirstOrDefault มิฉะนั้นจะมีข้อผิดพลาดรันไทม์
TruthOf42

2
@ TruthOf42 มันไม่น่าเป็นไปได้ GroupByไม่สร้างกลุ่มว่างดูความคิดเห็นก่อนหน้าของฉัน ส่วนใหญ่รหัสของคุณมีมากกว่าสิ่งที่คุณเห็นที่นี่ บางทีคุณอาจมีเช่นกันหรือเงื่อนไขในการที่Where First
Daniel Hilgarth

26

MoreLinq มีDistinctByวิธีที่คุณสามารถใช้:

มันจะช่วยให้คุณทำ:

var results = table1.DistictBy(row => row.Text);

การใช้วิธีการ (การตรวจสอบข้อโต้แย้งสั้น) มีดังนี้:

private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

ขอโทษฉันไม่กระตือรือร้นที่จะใช้ equalityComparer
Megha Jain

@MeghaJain เอ้อจะใช้อย่างใดอย่างหนึ่งโดยไม่คำนึงถึงGroupByความต้องการเช่นกัน ทั้งสองวิธีจะใช้ค่าเริ่มต้นEqualityComparerหากไม่มีให้
Servy

9
ถูกต้องฉันถ้าฉันผิด แต่สิ่งนี้ชัดเจนในความทรงจำไม่ใช่ใน DB? ไม่สามารถนำไปสู่การสแกนเต็มรูปแบบที่ไม่พึงประสงค์ได้หรือ
Kek

@Kek ไม่เพราะผลตอบแทนคุณจะหยุดที่องค์ประกอบที่แตกต่างแรก ในที่สุดใช่คุณจะโหลดแต่ละคีย์ใน HashSet แต่เนื่องจากเป็น IEnumerable และ IEnumerable out คุณจะได้รับไอเท็มเหล่านั้นเท่านั้น หากคุณกำลังพูดถึง LINQ กับ SQL แล้วใช่จะทำการสแกนตาราง
PRMan

12

แต่ฉันต้องการผลลัพธ์ที่ r.text ไม่ซ้ำกัน

ฟังดูราวกับว่าคุณต้องการสิ่งนี้:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

นี้จะเลือกแถวที่Textไม่ซ้ำกัน


7

แดเนียล Hilgarthคำตอบ 's ข้างต้นนำไปสู่System.NotSupportedข้อยกเว้นด้วยเอนทิตีกรอบ ด้วยEntity-Frameworkมันจะต้องเป็น:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

3

มีการถกเถียงกันมากมายในหัวข้อนี้

คุณสามารถหาหนึ่งในพวกเขาที่นี่ :

คำแนะนำที่ได้รับความนิยมมากที่สุดอย่างหนึ่งคือวิธี Distinct ที่ใช้แสดงออกเป็นแลมบ์ดาเป็นพารามิเตอร์ที่ @Servy ได้ชี้ให้เห็น

สถาปนิกหัวหน้าของ C # Anders Hejlsberg ได้แนะนำวิธีการแก้ปัญหาที่นี่ อธิบายว่าทำไมทีมงานกรอบการออกแบบจึงตัดสินใจไม่เพิ่มส่วนเกินของวิธี Distinct ที่ใช้แลมบ์ดา


2

จากสิ่งที่ฉันได้พบแบบสอบถามของคุณส่วนใหญ่จะถูกต้อง เพียงแค่เปลี่ยน "select r" เป็น "select r.Text" คือทั้งหมดและที่ควรจะแก้ปัญหา นี่คือวิธีที่ MSDN จัดทำเอกสารว่าควรใช้งานอย่างไร

Ex:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();

คุณเปลี่ยนคำสั่ง "select" ที่อาจไม่ต้องการในกรณีนี้
faza



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