목록의 모든 요소가 고유한지 확인


104

목록의 모든 요소가 고유한지 확인하는 가장 좋은 방법은 무엇입니까 (기존 방식과 같이 가장 좋은 방법)?

a를 사용하는 현재 접근 방식 Counter은 다음과 같습니다.

>>> x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
>>> counter = Counter(x)
>>> for values in counter.itervalues():
        if values > 1: 
            # do something

더 잘할 수 있습니까?

답변:


164

가장 효율적이지는 않지만 간단하고 간결합니다.

if len(x) > len(set(x)):
   pass # do something

아마도 짧은 목록의 경우 큰 차이를 만들지 않을 것입니다.


이게 내가하는 일이기도하다. 아마도 큰 목록에는 효율적이지 않을 것입니다.
tkerwin 2011 년

반드시 그런 것은 아닙니다. 목록에 반복 요소가있는 경우 조건부 본문이 실행됩니다 (예제에서 "#do something").
yan

2
충분히 공정하고 좋은 솔루션입니다. 거의 500 개 미만의 요소를 처리하고 있으므로 원하는 작업을 수행해야합니다.
user225312 2011 년

4
긴 목록과 효율성에 대해 걱정하는 경우, 이것은 이다 (모든 요소가 검사를 필요로하는 곳에) 실제로 고유의 긴 목록에 대한 효율적입니다. 초기 종료 솔루션은 실제로 고유 한 목록에 대해 더 오래 걸립니다 (내 테스트에서 약 2 배 더 오래). 따라서 대부분의 목록이 고유 할 것으로 예상되는 경우이 간단한 세트 길이 확인 솔루션을 사용하십시오. 대부분의 목록이 고유하지 않을 것으로 예상되는 경우 조기 종료 솔루션을 사용하십시오. 사용할 것은 사용 사례에 따라 다릅니다.
Russ

이 대답은 좋습니다. 그러나 여기서주의해야합니다. len(x) > len(set(x))의 요소 x가 고유하지 않으면 True 입니다. 이 질문의 제목은 정반대입니다. "목록의 모든 요소 고유한지 확인"
WhyWhat

96

다음은 조기 종료를 수행 할 2 줄입니다.

>>> def allUnique(x):
...     seen = set()
...     return not any(i in seen or seen.add(i) for i in x)
...
>>> allUnique("ABCDEF")
True
>>> allUnique("ABACDEF")
False

x의 요소가 해시 할 수없는 경우 다음 목록을 사용해야합니다 seen.

>>> def allUnique(x):
...     seen = list()
...     return not any(i in seen or seen.append(i) for i in x)
...
>>> allUnique([list("ABC"), list("DEF")])
True
>>> allUnique([list("ABC"), list("DEF"), list("ABC")])
False

5
+1 깨끗하고 필요하지 않은 경우 전체 목록을 반복하지 않습니다.
Kos

@ paul-mcguire : Apache 2.0 호환 라이선스 (예 : Apache 2, 2 / 3-line BSD, MIT, X11, zlib)에 따라이 코드 스 니펫에 라이선스를 부여 하시겠습니까? 사용중인 Apache 2.0 프로젝트에서 사용하고 싶습니다. StackOverflow의 라이선스 조건이 fubar 이므로 원본 작성자로 요청합니다.
라이언 Parman

MIT 라이센스를 사용하여 다른 코드를 내놓았으므로이 코드에서 저에게 효과적입니다. 특별히해야 할 일이 있습니까?
PaulMcG 2016 년

21

조기 종료 솔루션은 다음과 같습니다.

def unique_values(g):
    s = set()
    for x in g:
        if x in s: return False
        s.add(x)
    return True

그러나 작은 경우 또는 조기 종료가 일반적인 경우가 아니라면 len(x) != len(set(x))가장 빠른 방법이 될 것으로 기대 합니다.


특별히 최적화를 찾고 있지 않았기 때문에 다른 답변을 수락했습니다.
user225312 2011 년

2
다음에 다음 줄을 추가하여 줄일 수 있습니다 s = set().return not any(s.add(x) if x not in s else True for x in g)
Andrew Clark

len(x) != len(set(x))조기 퇴장이 흔하지 않은 경우 이보다 더 빠를 것으로 기대하는 이유를 설명해 주 시겠습니까? 두 작업 모두 O (len (x)) 아닌가요? ( x원래 목록은 어디에 있습니다 )
Chris Redford

오, 알겠습니다if x in s . O (len (x)) for 루프 내부 를 확인하기 때문에 메서드가 O (len (x)) 가 아닙니다 .
Chris Redford

15

속도 :

import numpy as np
x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
np.unique(x).size == len(x)

12

모든 항목을 세트에 추가하고 길이를 확인하는 것은 어떻습니까?

len(set(x)) == len(x)

1
yan, 아야 1 초 후에 대답했습니다. 짧고 달다. 이 솔루션을 사용하지 않는 이유가 있습니까?
jasonleonhard

모든 시퀀스 (특히 생성기)가 len().
PaulMcG

9

A와 대안 set, 당신은을 사용할 수 있습니다 dict.

len({}.fromkeys(x)) == len(x)

9
나는 세트에 대한 dict를 사용하는 것의 이점이 전혀 없다고 생각합니다. 불필요하게 복잡한 것 같습니다.
metasoarous

3

sorted 및 groupby를 사용하는 또 다른 접근 방식 :

from itertools import groupby
is_unique = lambda seq: all(sum(1 for _ in x[1])==1 for x in groupby(sorted(seq)))

정렬이 필요하지만 첫 번째 반복 값에서 종료됩니다.


해싱은 빠른 정렬보다
IceArdor

groupby이 답변을 사용하여 동일한 솔루션을 게시하기 위해 여기에 왔습니다 . 이것은 단일 표현식이고 추가 변수 나 루프 문을 필요로하지 않고 내장 도구와 함께 작동하기 때문에 이것이 가장 우아하다고 생각합니다.
Lars Blumberg

1
목록에 정렬 ​​할 수없는 임의의 개체가 포함 id()된 경우이 기능을 사용하여 정렬 할 수 있습니다. groupby()작업을 위한 전제 조건입니다 .groupby(sorted(seq), key=id)
Lars Blumberg

3

재미를위한 재귀 O (N 2 ) 버전 은 다음과 같습니다 .

def is_unique(lst):
    if len(lst) > 1:
        return is_unique(s[1:]) and (s[0] not in s[1:])
    return True

2

다음은 재귀 적 조기 종료 함수입니다.

def distinct(L):
    if len(L) == 2:
        return L[0] != L[1]
    H = L[0]
    T = L[1:]
    if (H in T):
            return False
    else:
            return distinct(T)    

기능적 스타일의 접근 방식을 사용하면서 이상한 (느린) 변환을 사용하지 않고도 충분히 빠릅니다.


1
H in T선형 검색 T = L[1:]을 수행하고 목록의 슬라이스 부분을 복사하므로 큰 목록에서 제안 된 다른 솔루션보다 훨씬 느립니다. 제 생각에는 O (N ^ 2)이고 나머지는 대부분 O (N) (세트) 또는 O (N log N) (정렬 기반 솔루션)입니다.
Blckknght 2013

1

이건 어때요

def is_unique(lst):
    if not lst:
        return True
    else:
        return Counter(lst).most_common(1)[0][1]==1

0

Yan의 구문 (len (x)> len (set (x)))을 사용할 수 있지만 set (x) 대신 함수를 정의하십시오.

 def f5(seq, idfun=None): 
    # order preserving
    if idfun is None:
        def idfun(x): return x
    seen = {}
    result = []
    for item in seq:
        marker = idfun(item)
        # in old Python versions:
        # if seen.has_key(marker)
        # but in new ones:
        if marker in seen: continue
        seen[marker] = 1
        result.append(item)
    return result

그리고 len (x)> len (f5 (x))를 수행합니다. 이것은 빠르며 주문 보존이기도합니다.

코드는 http://www.peterbe.com/plog/uniqifiers-benchmark 에서 가져 왔습니다.


이 f5 기능은 속도에 더 최적화 된 세트를 사용하는 것보다 느립니다. 이 코드는 값 비싼 "추가"작업으로 인해 목록이 정말 커지면 중단되기 시작합니다. 와 같은 큰 목록의 경우 x = range(1000000) + range(1000000)set (x)를 실행하는 것이 f5 (x)보다 빠릅니다. 주문은 질문의 요구 사항은 아니지만 sorted (set (x)) 실행도 f5 (x)보다 여전히 빠릅니다
OkezieE

0

Pandas 데이터 프레임에서 유사한 접근 방식을 사용하여 열 내용에 고유 한 값이 포함되어 있는지 테스트합니다.

if tempDF['var1'].size == tempDF['var1'].unique().size:
    print("Unique")
else:
    print("Not unique")

나에게 이것은 백만 개가 넘는 행을 포함하는 날짜 프레임의 int 변수에서 즉각적입니다.


0

위의 모든 대답은 좋지만 30 초의 파이썬all_unique 예제 를 사용하는 것을 선호합니다.

set()중복을 제거하려면 주어진 목록 에서 사용 하고 목록의 길이와 길이를 비교해야합니다.

def all_unique(lst):
  return len(lst) == len(set(lst))

그것은 반환 True단순 목록에있는 모든 값이있는 경우 unique, False그렇지 않으면

x = [1,2,3,4,5,6]
y = [1,2,2,3,4,5]
all_unique(x) # True
all_unique(y) # False

-3

초보자를 위해 :

def AllDifferent(s):
    for i in range(len(s)):
        for i2 in range(len(s)):
            if i != i2:
                if s[i] == s[i2]:
                    return False
    return True

세트를 사용할 때 작성할 필요가없는 코드를 아주 잘 보여주기 때문에이 답변을 좋아합니다. 나는 그것을 "초보자를위한 것"이라고 부르지 않을 것이다. 나는 초보자들이 그것을 올바른 방법으로 먼저 배워야한다고 믿는다. 하지만 그런 코드를 다른 언어로 작성하는 데 익숙한 경험이없는 개발자를 만났습니다.
cessor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.