テーブルの1つのフィールドのみに基づくLinqでの区別


133

Linqで.distinctを使用して、テーブルの1つのフィールドに基づいて結果を取得しようとしています(したがって、テーブルからの重複したレコード全体を必要としません)。

私は次のようにdistinctを使用して基本的なクエリを書くことを知っています:

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

しかし、r.text重複しない結果が必要です。


区別するフィールドを指定する必要があります
。msdn.microsoft.com/ en

回答:


300

これを試して:

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

これにより、テーブルがグループ化されText、各グループの最初の行が使用され、Textが異なる行になります。


2
groupbyに複数のフィールドがある場合はどうなりますか?

6
@ user585440:その場合は、次のようなので、匿名型を使用しますtable1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
ダニエルHilgarth

2
はい、あなたは正しいと私はすでにそれを見つけました。とにかくありがとう。また、Select(x => x.First())がクラッシュを引き起こす可能性があることもわかりました。Select(x => x.FirstOrDefault());に変更することをお勧めします。

6
FirstOrDefaultを使用する必要がありました。そうでない場合、実行時エラーが発生しました
TruthOf42 '27

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

申し訳ありませんが、equityComparerを使用したくありませんでした。
Megha Jain 2013年

@MeghaJainまあ、いずれかがGroupBy必要と同様に、いずれかが使用されます。EqualityComparer何も指定されていない場合、どちらの方法でもデフォルトが使用されます。
2013年

9
まあ、私が間違っている場合は私を修正しますが、ここでのこの違いはDBではなくメモリで行われますか?これは、望ましくないフルスキャンにつながりませんか?
Kek

@Kek。いいえ、イールドリターンのため、最初の個別の要素で停止します。最終的に、はい、各キーをHashSetにロードしますが、それはIEnumerable inおよびIEnumerable outであるため、これらの項目のみを取得します。LINQ to SQLについて話している場合、はい、これはテーブルスキャンを実行します。
PRMan

12

しかし、r.textが複製されない結果が必要です

あなたがこれを望んでいるかのように聞こえます:

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

これにより、Textが一意である行が選択されます。


7

上記のDaniel Hilgarthの答えは、Entity-FrameworkのSystem.NotSupported例外につながりますエンティティフレームワーク、それがなければなりません。

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

3

このトピックに関しては多くの議論があります。

あなたはここでそれらの1つを見つけることができます

最も一般的な提案の1つは、@ Servyが指摘したように、ラムダ式をパラメーターとして取るDistinctメソッドです。

C#のチーフアーキテクトであるAnders Hejlsbergが、ここでの解決策を提案しています。また、フレームワーク設計チームがラムダを使用するDistinctメソッドのオーバーロードを追加しないことにした理由も説明します。


2

私が見つけたものから、あなたのクエリはほとんど正しいです。「select r」を「select r.Text」に変更するだけで問題は解決します。これは、MSDNがどのように機能するかを文書化した方法です。

例:

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

あなたは、この場合には望ましいことではないかもしれ文を「選択」に変更
faza

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

-2

このコードを試してください:

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

-5

あなたはこれを試すことができます:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.