목록의 모든 값이 고유한지 테스트


90

작은 바이트 목록이 있고 모두 다른 값인지 테스트하고 싶습니다. 예를 들어 다음과 같습니다.

List<byte> theList = new List<byte> { 1,4,3,6,1 };

모든 값이 구별되는지 확인하는 가장 좋은 방법은 무엇입니까?


2
이것은 일반적인 교실 질문이므로 질문으로 대답하겠습니다. 분류 되었다면 어떻게 하시겠습니까?
ctrl-alt-delor

답변:


168
bool isUnique = theList.Distinct().Count() == theList.Count();

궁금한 점 : 이것의 공간 및 시간 요구 사항은 무엇입니까?
dtb

10
@dtb 는 약 O (N)이어야합니다 . 물론 이것이 "작은 목록"이라는 점을 고려하면 거의 모든 알고리즘에서 매우 빠릅니다. IMO는 가독성과 간결함에서 승리하며 속도는 문제가 아니기 때문에 완벽합니다.
Tim S.

2
이것은 할 수있는 것보다 LEFF 효율적이다
Jodrell

74

여기에 Enumerable.Distinct+ 보다 더 효율적인 또 다른 접근법이 있습니다 Enumerable.Count(시퀀스가 컬렉션 유형이 아닌 경우 더욱 그렇습니다). 그것은 사용하는 HashSet<T>중복을 제거하는이 조회에서 매우 효율적이며 카운트 속성이 있습니다 :

var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;

또는 다른-더 미묘하고 효율적인 접근법 :

var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);

HashSet<T>.Add반환 false는 이미 이후 요소를 추가 할 수없는 경우 HashSet. Enumerable.All첫 번째 "거짓"에서 중지합니다.


1
너무 간단하고 분명합니다. 왜 먼저 생각하지 않았습니까? :) 저는이 한 줄짜리 단위 테스트를 사용하여 멋진 코드로 생성 된 1,000 만 개의 요소가 정말 독특하다는 것을 확인했습니다 Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));. 그들은 있었다 : 당신 팀을 위해 : 1이다
grapkulec

1
이 질문에 답변을 시도하지만 선생님 작동하지 않습니다 : stackoverflow.com/questions/34941162/...
학습 - Overthinker-혼란

이이어야한다 :bool allDifferent = theList.All(s => diffChecker.Add(s))
마이크 넬슨

2
아니요, 필요하지 않습니다. 이 경우 대표자를 직접 전달할 수 있습니다
Tim Schmelter 2017

1
@ AndréReichelt-방금 귀하의 코드를 열었고 세 번째 시나리오 ( List.All(HashSet.Add))는 거의 모든 경우에 다른 두 시나리오 보다 훨씬 빠른 것 같습니다
Kyle Delaney

6

좋습니다. 여기에 표준 .Net을 사용하는 가장 효율적인 방법이 있습니다.

using System;
using System.Collections.Generic;

public static class Extension
{
    public static bool HasDuplicate<T>(
        this IEnumerable<T> source,
        out T firstDuplicate)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }

        var checkBuffer = new HashSet<T>();
        foreach (var t in source)
        {
            if (checkBuffer.Add(t))
            {
                continue;
            }

            firstDuplicate = t;
            return true;
        }

        firstDuplicate = default(T);
        return false;
    }
}

기본적으로 전체 시퀀스를 두 번 열거하는 요점은 첫 번째 복제본을 찾는 것뿐입니다.

빈 단일 요소 시퀀스를 특수 케이스로 처리하여이를 더 최적화 할 수 있지만 최소한의 이득으로 가독성 / 유지 보수 가능성이 떨어집니다.


중복 값을 반환하는 것이
좋습니다.

여기에서 세 가지 솔루션을 테스트했으며 실제로이 페이지에서 가장 효율적입니다. 그래도 몇 가지 오타가 있습니다 (예 : sequence이어야 함 source). 이 고정되면하지만 좋은 작품
마이크 넬슨

@mikenelson, 그것은 더 나은해야한다
Jodrell

2
가독성 if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }을 위해 루프에 있어야한다고 생각합니다 .
tia

2

Distinct사용 과 유사한 논리 GroupBy:

var isUnique = theList.GroupBy(i => i).Count() == theList.Count;

이것은 theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;Distinct ()가 허용하지 않는 동안 속성과 관련하여 고유성을 확인하려는 경우 유용 합니다.
Rev1.0

1

또한 할 수있는 일 : Hashset 사용

var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));

            if (uniqueIds.Count != originalList.Count)
            {
            }

0

많은 해결책이 있습니다.

그리고 "juergen d"와 "Tim Schmelter"로 LINQ를 사용한 더 아름다운 것들은 의심 할 여지가 없습니다.

그러나 "복잡성"과 속도를 노출하지 않는다면 가장 좋은 해결책은 직접 구현하는 것입니다. 해결책 중 하나는 N 크기의 배열을 만드는 것입니다 (바이트의 경우 256). 그리고 배열을 반복하고 모든 반복에서 값이 1이면 일치하는 숫자 인덱스를 테스트합니다. 그렇다면 이미 배열 인덱스를 증가시키고 따라서 배열이 구별되지 않음을 의미합니다. 그렇지 않으면 배열 셀을 증가시키고 계속 확인합니다. .


2
256 비트 = 32 바이트 = 8 개의 정수로 비트 벡터를 사용할 수 있습니다. 그러나 Big O = O (n)은 다른 답변에서 제안한 Hashet을 사용하는 것과 동일합니다.
BrokenGlass 2013-08-18

이것은 O (n)이므로 아마도 가장 빠를 것입니다. 당신이 갈 때 또는 마지막에 확인하는 것이 가장 빠를까요? 나는 결국 최악의 경우를 개선 할 것이라고 생각하지만, 당신이 갈수록 평균과 최상의 경우를 개선 할 수 있습니다). 중복이 없으면 최악의 성능입니다. 또한 더 큰 데이터 유형의 경우 제대로 작동하지 않습니다. 16 비트 유형의 경우 64k 비트 (8k 바이트)를 사용해야하지만 더 큰 데이터 유형의 경우 메모리 사용량이 어리석기 시작합니다. 그러나 나는 8bit 값에 대해이 대답을 좋아합니다.
ctrl-alt-delor

1
@TamusJRoyce 경우 4294967296 가능성을 저장하려면 42MB가 아닌 4GB가 필요합니다 (또는 512MB의 비트 마스킹 사용)
tigrou

내가 무슨 생각을했는지 잘 모르겠다. "모든 4294967296 가능성을 유지하려면 42MB 이상의 메모리를 할당하십시오. 간단한 버킷 카운터를 사용하십시오. 또는 비트 마스킹 xor를 사용하여 비트가 참에서 거짓으로 변경되었는지 확인하십시오. 42MB + / 8 = 5MB + 오늘날의 하드웨어에서는 비용이 너무 많이 드는 것 같습니다. 그러나 언젠가 이것이 공덕을 가질 수 있습니다. " 실제로 관련 댓글이 아닙니다. Hashset이 가장 좋습니다. 매우 큰 배열을 처리하는 경우 매우 큰 메모리 조각이 예상됩니다. 그러나 이러한 이상한 경우에서는 CRC 알고리즘을 사용한 유전 적 방법이 더 좋습니다. 다항식에 매핑하십시오. 가까운 경우 평가하십시오. @tigrou 감사합니다!
TamusJRoyce

0

그리고 중복 된 값을 찾으려면 또 다른 솔루션입니다.

var values = new [] { 9, 7, 2, 6, 7, 3, 8, 2 };

var sorted = values.ToList();
sorted.Sort();
for (var index = 1; index < sorted.Count; index++)
{
    var previous = sorted[index - 1];
    var current = sorted[index];
    if (current == previous)
        Console.WriteLine(string.Format("duplicated value: {0}", current));
}

산출:

duplicated value: 2
duplicated value: 7

http://rextester.com/SIDG48202


0

IEnumerable (aray, list 등)이 다음과 같이 고유한지 확인합니다.

var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.