테이블의 한 필드 만 기준으로 Linq에서 구별


133

Linq에서 .distinct를 사용하여 테이블의 한 필드를 기반으로 결과를 얻으려고합니다 (따라서 테이블에서 전체 복제 된 레코드가 필요하지 않음).

다음과 같이 distinct를 사용하여 기본 쿼리를 작성하는 것을 알고 있습니다.

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

하지만 r.text중복되지 않은 결과가 필요합니다 .


당신은 구별되어야 할 내용 필드에 지정해야합니다 참조 msdn.microsoft.com/en-us/library/bb348436.aspx
Antarr 버드

답변:


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());
Daniel Hilgarth

2
예, 당신 말이 맞아 이미 찾았습니다 어쨌든 고마워 또한 Select (x => x.First ())가 충돌을 일으킬 수 있음을 알았습니다. Select (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 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-FrameworkSystem.NotSupported예외로 이어집니다 . Entity-Framework를 사용하면 다음과 같아야 합니다.

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

3

이 주제와 관련하여 많은 토론이 있습니다.

당신은 그들 중 하나를 찾을 수 있습니다 여기에 :

가장 인기있는 제안 중 하나는 @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();

이 경우에는 원하지 않는 "select"문을 변경했습니다
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.