Beda dalam Linq berdasarkan hanya satu bidang tabel


133

Saya mencoba menggunakan .distinct di Linq untuk mendapatkan hasil berdasarkan pada satu bidang tabel (jadi tidak memerlukan seluruh rekaman yang digandakan dari tabel).

Saya tahu menulis kueri dasar menggunakan berbeda sebagai berikut:

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

tapi saya butuh hasil di mana r.texttidak digandakan.


Anda perlu menentukan bidang apa yang ingin Anda bedakan, lihat msdn.microsoft.com/en-us/library/bb348436.aspx
Antarr Byrd

Jawaban:


300

Coba ini:

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

Ini akan mengelompokkan tabel dengan Textdan menggunakan baris pertama dari masing-masing kelompok sehingga menghasilkan baris Textyang berbeda.


2
Bagaimana jika groupby memiliki lebih dari 1 bidang?

6
@ user585440: Dalam hal ini, Anda menggunakan jenis anonim seperti:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth

2
Ya, Anda benar dan saya sudah menemukannya. Bagaimanapun, terima kasih. Dan saya juga menemukan bahwa Select (x => x.First ()) dapat menyebabkan crash. Lebih baik mengubah ke Select (x => x.FirstOrDefault ());

6
Saya harus menggunakan FirstOrDefault atau ada kesalahan runtime
TruthOf42

2
@ TruthOf42 Itu agak tidak mungkin. GroupBytidak membuat grup kosong, lihat komentar saya sebelumnya. Kemungkinan besar, kode Anda mengandung lebih dari apa yang Anda lihat di sini. Mungkin Anda memiliki Wherejuga atau kondisi untuk First.
Daniel Hilgarth

26

MoreLinq memiliki metode DistinctBy yang dapat Anda gunakan:

Ini akan memungkinkan Anda untuk melakukan:

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

Implementasi metode (singkat validasi argumen) adalah sebagai berikut:

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

maaf saya tidak ingin menggunakan equalityComparer.
Megha Jain

@ Maghain Yah, satu akan digunakan terlepas, seperti GroupBykebutuhan juga. Kedua metode akan menggunakan default EqualityComparerjika tidak ada yang disediakan.
Servy

9
Ya, benar kalau saya salah, tetapi perbedaan ini dilakukan di memori, bukan di DB? Tidak bisakah ini menyebabkan pemindaian penuh yang tidak diinginkan?
Kek

@Kek. Tidak, karena pengembalian hasil, Anda akan berhenti di elemen berbeda pertama. Akhirnya, ya, Anda akan memuat setiap kunci ke dalam HashSet, tetapi karena IEnumerable in dan IEnumerable out, Anda hanya akan mendapatkan item-item itu. Jika Anda berbicara tentang LINQ ke SQL, maka ya, ini akan melakukan pemindaian tabel.
PRMan

12

tapi saya butuh hasil di mana r.text tidak digandakan

Kedengarannya seperti Anda menginginkan ini:

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

Ini akan memilih baris tempat yang Textunik.


7

Jawaban Daniel Hilgarth di atas mengarah ke System.NotSupportedpengecualian With Entity-Framework . Dengan Entity-Framework , harus:

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

3

Ada banyak diskusi seputar topik ini.

Anda dapat menemukannya di sini :

Salah satu saran paling populer adalah metode Distinct yang menggunakan ekspresi lambda sebagai parameter seperti yang ditunjukkan oleh @Servy.

Arsitek kepala C #, Anders Hejlsberg telah menyarankan solusi di sini . Juga menjelaskan mengapa tim desain kerangka kerja memutuskan untuk tidak menambahkan kelebihan metode Distinct yang membutuhkan lambda.


2

Dari apa yang saya temukan, permintaan Anda sebagian besar benar. Cukup ubah "select r" menjadi "select r.Text" adalah segalanya dan itu akan menyelesaikan masalah. Ini adalah bagaimana MSDN mendokumentasikan cara kerjanya.

Ex:

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

Anda mengubah pernyataan "pilih" yang mungkin tidak diinginkan dalam kasus ini
faza

1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });

-2

coba kode ini:

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

-5

Anda dapat mencoba ini:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.