Distinct 도저히 모르겠습니다.

LINQ 학습중 이해가 안되는 부분이 있어 질문올립니다.

  1. 무엇을 하고자 하는지.
    -. 입력받은 컬랙션들 중에서 가장 중복이 많은 컬렉션 반환
    -. 중복이 동일하다면, 가장 적은 컬랙션 반환
    -. 빈 컬랙션일 경우 null 반환

*{1,2,3,4} - 중복 0 개
*{1,2,3,3,4,4,4} - 중복 3개 (3 - 1개, 4 - 2개)
*{1,2,3,3,4,4,4,5,6,7} - 중복 3개 (3 - 1개, 4 - 2개)

결과
: 두번째 컬랙션 {1,2,3,3,4,4,4}

  1. 현재 작성한 코드 중 문제가 되는 부분
    private static void Print(string title, List<List<int>> result)
    {
      Console.WriteLine($"============= {title}");

      for (int i = 0; i < result.Count(); i++)
      {
        Console.WriteLine(
          string.Join(",",
            Array.ConvertAll(result.ElementAt(i)
              .ToArray(), i => i.ToString()))
          );
      }
    }

    private static void Test()
    {
      var collections = new List<List<int>> {
        new List<int> { 1, 2, 3, 4 },    // 4 - 4 = 0
        new List<int> { 1, 2, 3, 3, 4, 4, 4 },  // 7 - 4 = 3  
        new List<int> { 1, 2, 3, 3, 4, 4, 4, 5, 6, 7 } // 10 - 7 = 3
      };

      //var result = collections
      //     .OrderBy(list => list.Count() - list.Distinct().Count())
      //     .ThenByDescending(list => list.Count())
      //     .ToList()
      //;//.LastOrDefault();

      //Print("Result ***", result);

      var result1 = collections
           .OrderBy(list => list.Count() - list.Distinct().Count())
           .ToList()
        ;//.LastOrDefault();

      Print("OrderBy ***", result1);

      var result2 = collections
        .OrderBy(list => list.Count() - list.Distinct().Count())
        .ThenByDescending(list => list.Count())
        .ToList()
        ;//.LastOrDefault();

      Print("ThenByDescending ***", result2);
    }

============= OrderBy ***
1,2,3,4
1,2,3,3,4,4,4
1,2,3,3,4,4,4,5,6,7
============= ThenByDescending ***
1,2,3,4
1,2,3,3,4,4,4,5,6,7
1,2,3,3,4,4,4

여기서 ThenByDescending 의 결과가 왜 이렇게 나오는지 이해가 안됩니다;;;;
단순히 Count() 내림차순 정렬이면 10, 7, 4 순으로 정렬되야 하는게 맞지 않나요???

  • 기대하는 동작
    list.Count() 내림차순 10, 7, 4 인데, 4,10,7이 되는 이유를 알고 싶습니다.
1개의 좋아요

OrderBy가 우선하기 때문입니다.

2개의 좋아요

아래 코드를 참고해 보세요.

var collections = new List<List<int>> {
        new List<int> { 1, 2, 3, 4 },    // 4 - 4 = 0
        new List<int> { 1, 2, 3, 3, 4, 4, 4 },  // 7 - 4 = 3  
        new List<int> { 1, 2, 3, 3, 4, 4, 4, 5, 6, 7 } // 10 - 7 = 3
};

var result = collections
    .Select(x => (Num: x.Count - x.ToHashSet().Count, List: x))
    // 중복이 가장 많은 순으로
    .OrderByDescending(x => x.Num) 
    // 그 중 가장 적은 컬렉션
    .ThenBy(x => x.Num)
    .Select(x => x.List)
    .FirstOrDefault();
    
if (result is not null)
    PrintCollection(result);

static void PrintCollection<T>(ICollection<T> collection)
{
    Console.Write("{ ");
    Console.Write(string.Join(", ", collection));
    Console.WriteLine(" }");
}

| 결과

{ 1, 2, 3, 3, 4, 4, 4 }
2개의 좋아요

ThenBy는 OrderBy로 이미 한 번 정렬된 IOrderedEnumerable에서 2차 3차로 정렬하는 메서드입니다.

2개의 좋아요

코드가 잘못되었네요. 아래의 LINQ가 조건에 맞습니다.

var result = collections
    .OrderByDescending(x => x.Count - x.ToHashSet().Count)
    .ThenBy(x => x.Count)
    .FirstOrDefault();
3개의 좋아요

list_0.Count = 4 new List { 1, 2, 3, 4 }, // 4 - 4 = 0
list_1.Count = 7 new List { 1, 2, 3, 3, 4, 4, 4 }, // 7 - 4 = 3
list_2.Count = 10 new List { 1, 2, 3, 3, 4, 4, 4, 5, 6, 7 } // 10 - 7 = 3

OrderByDescending(x => x.Count - x.ToHashSet().Count)
// 결과 : list1 (7), list2 (10) , list0 (4) —> OK!!
ThenBy(x => x.Count)
// 결과 : list1 (7), list2 (10) , list0 (4) —> ??? 여기서 왜 Count 순으로 정렬이 안되는 건지요??

제가 생각한 결과는…Count로 오름차순 정렬이니까
list0 (4), list1 (7), list2 (10)
이라서요;;;;

언어를 깊이있게 알 지 못하긴 하는데 당연하다고 생각되던게 아니여서 …질문드립니다;;

1개의 좋아요

OrderByDescending 로 정렬 완료된 것을 전체 데이터를 기준으로
다시 정렬 하는 것이 아니라

OrderByDescending 로 정렬 하면서 Count순으로 추가 정렬 하는 것입니다.

var collections = new List<List<int>> {
                new List<int> { 1, 2, 3, 4 },    // 4 - 4 = 0
                new List<int> { 1, 2, 3, 3, 4, 4, 4 },  // 7 - 4 = 3
                new List<int> { 1, 1, 1, 1 },  // 4 - 1 = 3
                new List<int> { 1, 2, 3, 3, 4, 4, 4, 5, 6, 7 } // 10 - 7 = 3
            };

중복 갯수가 동일한 더 짧은 요소인 { 1, 1, 1, 1 } 을 하나 더 추가 하면 결과가 달라집니다.

OrderByDescending 정렬시
1, 2, 3, 3, 4, 4, 4
1, 1, 1, 1
.
.

순으로 정렬 하는 과정에서 ThenBy 로 Count로 추가 정렬이 다시 되어

1, 1, 1, 1
1, 2, 3, 3, 4, 4, 4

이렇게 재 정렬처리 되고

이후

동일하게
1, 2, 3, 3, 4, 4, 4, 5, 6, 7
1, 2, 3, 4
정렬 과정이 되어집니다.

3개의 좋아요

DB 쿼리의 ORDER BY 처럼 생각하시면 좋을거라 생각합니다.

GROUP BY 중복개수, 카운트

를 한다고 할때도 중복개수 순으로 정렬한 후, 같은 중복개수가 같은 함목에 대해 카운트로 추가 정렬이 됩니다.

Linq에서는 이를 OrderBy(OrderByDesendig)이 후 ThenBy(ThenByDesending)을 연결해 맞추는 구조입니다.

따라서 중복 개수가 많은 항목, 이 후 카은트가 적은 항목으로 한다면

OrderByDesending(중복개수 확인방법).ThenBy(카운트)

순으로 정렬을 지정해야 합니다.

3개의 좋아요

와…도움주신분들 모두 고맙습니다.

쫄아있어서 보여야 될게 안보였던거 같습니다.

select * from (select * from aaa order by count desc) as t order by count asc
요딴식으로 생각하고 있었네요.

새로운 방식, 구문도 알게되고 정말 고맙습니다~~

2개의 좋아요