목록의 모든 요소가 동일한 지 확인하십시오


389

다음 기능이 필요합니다.

입력 :list

출력 :

  • True 입력 목록의 모든 요소가 표준 항등 연산자를 사용하여 서로 같은 것으로 평가되는 경우;
  • False 그렇지 않으면.

공연 : 물론 불필요한 오버 헤드가 발생하지 않는 것을 선호합니다.

나는 그것이 최선일 것이라고 생각한다.

  • 목록을 반복
  • 인접한 요소를 비교
  • 그리고 AND모든 결과 부울 값

그러나 가장 파이썬적인 방법이 무엇인지 잘 모르겠습니다.


단락 기능이 없으면 초기 요소가 같지 않은 긴 입력 (~ 50 개 이상의 요소)에 대해서만 문제가됩니다. 이 문제가 자주 발생하는 경우 (목록의 길이에 따라 다름) 단락이 필요합니다. 최고의 단락 알고리즘은 @KennyTM 인 것 같습니다 checkEqual1. 그러나 이것에 대한 상당한 비용을 지불합니다.

  • 거의 동일한 성능의 목록에서 최대 20 배
  • 짧은 목록에서 최대 2.5 배 성능

초기에 같지 않은 요소를 가진 긴 입력이 발생하지 않거나 충분히 드물게 발생하는 경우 단락이 필요하지 않습니다. 그런 다음 @Ivo van der Wijk 솔루션이 가장 빠릅니다.


3
과 동일 a == b또는 같은 동일 a is b?
kennytm

1
솔루션이 빈 목록을 처리해야합니까? 그렇다면 무엇을 반환해야합니까?
Doug

1
a == b와 동일합니다. 빈 목록을 처리하고 True를 반환해야합니다.
최대

2
다른 권장 사항보다 느리다는 것을 알고 있지만 functools.reduce(operator.eq, a)제안되지 않은 것에 놀랐습니다 .
user2846495

답변:


420

일반적인 방법 :

def checkEqual1(iterator):
    iterator = iter(iterator)
    try:
        first = next(iterator)
    except StopIteration:
        return True
    return all(first == rest for rest in iterator)

짧막 한 농담:

def checkEqual2(iterator):
   return len(set(iterator)) <= 1

또한 하나의 라이너 :

def checkEqual3(lst):
   return lst[1:] == lst[:-1]

3 가지 버전의 차이점은 다음과 같습니다.

  1. 에서 checkEqual2내용 해쉬해야합니다.
  2. checkEqual1그리고 checkEqual2어떤 반복자를 사용할 수 있지만,checkEqual3 일련의 입력, 목록 또는 튜플 같은 일반적으로 콘크리트 용기를 취해야합니다.
  3. checkEqual1 차이가 발견되는 즉시 중지합니다.
  4. checkEqual1더 많은 Python 코드가 포함되어 있기 때문에 처음에 많은 항목이 동일한 경우 효율성이 떨어집니다.
  5. 이후 checkEqual2checkEqual3항상 O (N) 복사 작업을 수행 할 귀하의 의견의 대부분은 False를 반환한다면, 그들은 오래 걸릴 수 있습니다.
  6. 의 경우 checkEqual2checkEqual3는에서 비교 적응하기 힘들어 a == b하는 방법에 대해 a is b.

timeit 결과는 Python 2.7 및 (s1, s4, s7, s9 만 True를 반환해야 함)

s1 = [1] * 5000
s2 = [1] * 4999 + [2]
s3 = [2] + [1]*4999
s4 = [set([9])] * 5000
s5 = [set([9])] * 4999 + [set([10])]
s6 = [set([10])] + [set([9])] * 4999
s7 = [1,1]
s8 = [1,2]
s9 = []

우리는 얻는다

      | checkEqual1 | checkEqual2 | checkEqual3  | checkEqualIvo | checkEqual6502 |
|-----|-------------|-------------|--------------|---------------|----------------|
| s1  | 1.19   msec | 348    usec | 183     usec | 51.6    usec  | 121     usec   |
| s2  | 1.17   msec | 376    usec | 185     usec | 50.9    usec  | 118     usec   |
| s3  | 4.17   usec | 348    usec | 120     usec | 264     usec  | 61.3    usec   |
|     |             |             |              |               |                |
| s4  | 1.73   msec |             | 182     usec | 50.5    usec  | 121     usec   |
| s5  | 1.71   msec |             | 181     usec | 50.6    usec  | 125     usec   |
| s6  | 4.29   usec |             | 122     usec | 423     usec  | 61.1    usec   |
|     |             |             |              |               |                |
| s7  | 3.1    usec | 1.4    usec | 1.24    usec | 0.932   usec  | 1.92    usec   |
| s8  | 4.07   usec | 1.54   usec | 1.28    usec | 0.997   usec  | 1.79    usec   |
| s9  | 5.91   usec | 1.25   usec | 0.749   usec | 0.407   usec  | 0.386   usec   |

노트 :

# http://stackoverflow.com/q/3844948/
def checkEqualIvo(lst):
    return not lst or lst.count(lst[0]) == len(lst)

# http://stackoverflow.com/q/3844931/
def checkEqual6502(lst):
    return not lst or [lst[0]]*len(lst) == lst

1
감사합니다. 이것은 대안에 대한 정말 유용한 설명입니다. 성능 표를 다시 확인하십시오. 모두 msec 단위이며 올바른 셀의 숫자입니까?
최대

7
@max : 예. 1 msec = 1000 usec입니다.
kennytm

1
매우 큰 배열에 대한 메모리 사용량 분석, obj.__eq__when에 대한 호출을 최적화하는 기본 솔루션 lhs is rhs및 정렬되지 않은 정렬 된 목록을보다 빠르게 정렬 할 수있는 비 순차적 최적화를 잊지 마십시오 .
Glenn Maynard

3
Ivo van der Wijk는 메모리에서 설정 및 O (1)보다 약 5 배 빠른 시퀀스를위한 더 나은 솔루션을 제공합니다.
aaronasterling

2
itertools답변으로 추가 한 레시피 도 있습니다 . 타이밍 매트릭스에 던져 넣을 가치가 있습니다 :-).
mgilson

298

시퀀스 (반복 가능하지 않음)에서 작동하는 set ()을 사용하는 것보다 빠른 해결책은 단순히 첫 번째 요소를 계산하는 것입니다. 이것은 목록이 비어 있지 않은 것으로 가정합니다 (그러나 빈 목록에서 결과를 확인하고 결정하는 것은 쉽지 않습니다)

x.count(x[0]) == len(x)

몇 가지 간단한 벤치 마크 :

>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777

5
세상에, 이것은 설정된 솔루션보다 6 배 빠릅니다! (노트북의 초당 2 억 5 천 5 백만 요소 / 초). 왜??? 그리고 그것을 단락 시켜서 그것을 단락시킬 수있는 방법이 있습니까? (아마 ...)
max

1
list.count는 고도로 최적화 된 C 구현을 가지고 있으며 목록의 길이는 내부적으로 저장되므로 len ()도 저렴합니다. count ()를 단락시키는 방법은 없습니다. 정확한 수를 얻으려면 모든 요소를 ​​실제로 확인해야하기 때문입니다.
Ivo van der Wijk

x.count(next(x)) == len(x)컨테이너 x에서 작동하도록 변경할 수 있습니까 ? Ahh .. nm, .count는 시퀀스에만 사용 가능하다는 것을 알았습니다. 왜 다른 내장 컨테이너에 대해서도 구현되지 않습니까? 사전 내부 계산은 목록 내부보다 본질적으로 덜 의미가 있습니까?
최대

4
반복자의 길이가 없을 수 있습니다. 예를 들어 무한하거나 동적으로 생성 될 수 있습니다. 대부분의 반복자 장점을 제거하는 목록으로 변환하여 길이를 찾을 수 있습니다.
Ivo van der Wijk

죄송합니다. count이터 러블에 구현되지 않은 이유 len와 반복자에 사용할 수 없는 이유 가 아닙니다. 답은 아마도 감독 일뿐일 것입니다. 그러나 .count()시퀀스의 기본값 이 매우 느리기 때문에 (비 순수) 우리에게 관련 이 없습니다. 솔루션이 너무 빠른 이유는에서 count제공 한 C 구현에 의존하기 때문 list입니다. 따라서 countC에서 메소드 를 구현 하는 것이 반복 가능 하면 접근 방식의 이점이 있다고 생각 합니다.
최대

163

가장 간단하고 우아한 방법은 다음과 같습니다.

all(x==myList[0] for x in myList)

(예, 이것은 빈 목록으로도 작동합니다! 이것은 파이썬이 게으른 의미를 가진 몇 안되는 경우 중 하나이기 때문입니다.)

성능과 관련하여 가능한 빠른 시간 내에 실패하므로 무조건 최적입니다.


이것은 작동하지만 @KennyTM보다 약간 (1.5x) 느립니다 checkEqual1. 왜 그런지 잘 모르겠습니다.
최대

4
최대 : 아마 내가 최적화를 수행 귀찮게하지 않았기 때문에 first=myList[0] all(x==first for x in myList)아마
ninjagecko

myList [0]은 각 반복마다 평가된다고 생각합니다. >>> timeit.timeit ( 'all ([y == x [0] in x]])', 'x = [1] * 4000', 숫자 = 10000) 2.707076672740641 >>> timeit.timeit ( 'x0 = x [0]; all ([y == x에서 y의 경우 x0)] ','x = [1] * 4000 ', 숫자 = 10000) 2.0908854261426484
Matt Liberty

1
물론 최적화 first=myList[0]IndexError빈 목록에 던져 질 것이라는 점을 분명히해야 하므로, 언급 한 최적화에 대해 이야기 한 주석가는 빈 목록의 가장자리를 처리해야합니다. 그러나 원본은 괜찮습니다 ( 목록이 비어 있으면 평가되지 않기 때문에 x==myList[0]괜찮 all습니다).
ninjagecko

1
이것은 분명히 올바른 방법입니다. 모든 경우에 속도를 원한다면 numpy와 같은 것을 사용하십시오.
Henry Gomersall

45

세트 비교 작업 :

len(set(the_list)) == 1

를 사용 set하면 모든 중복 요소가 제거됩니다.


26

목록을 세트로 변환 할 수 있습니다. 세트는 복제본을 가질 수 없습니다. 따라서 원래 목록의 모든 요소가 동일하면 세트에는 하나의 요소 만 있습니다.

if len(sets.Set(input_list)) == 1
// input_list has all identical elements.

이것은 좋지만 단락되지 않으며 결과 목록의 길이를 계산해야합니다.
aaronasterling

15
왜 안돼 len(set(input_list)) == 1?
Nick Dandoulakis

2
@codaddict. 이는 처음 두 요소가 다른 경우에도 여전히 전체 검색을 완료 함을 의미합니다. 또한 O (k) 여분의 공간을 사용합니다. 여기서 k는 목록에서 고유 한 요소의 수입니다.
aaronasterling

1
@max. 세트 빌드는 C에서 발생하고 구현이 잘못 되었기 때문입니다. 최소한 생성기 표현식에서 수행해야합니다. 세트를 사용하지 않고 올바르게 수행하는 방법은 KennyTM의 답변을 참조하십시오.
aaronasterling

1
sets.Set는 "버전 2.6부터 사용되지 않습니다. 내장 세트 / 냉동 세트 유형이이 모듈을 대체합니다." ( docs.python.org/2/library/sets.html에서 )
Moberg

21

가치있는 것을 위해, 이것은 최근 파이썬 아이디어 메일 링리스트 에 나타났습니다 . 이미이 작업을 수행 하는 itertools 레시피 가 있음이 밝혀졌습니다 . 1

def all_equal(iterable):
    "Returns True if all the elements are equal to each other"
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

아마 그것은 아주 잘 수행하고 몇 가지 좋은 속성을 가지고 있습니다.

  1. 단락 : 첫 번째 같지 않은 항목을 찾 자마자 iterable에서 항목 소비를 중지합니다.
  2. 항목을 해시 가능하지 않아도됩니다.
  3. 게으 르며 검사를 수행하기 위해 O (1) 추가 메모리 만 필요합니다.

1 다시 말해, 솔루션을 제공한다고해서 크레딧을받을 수 없으며 심지어 솔루션을 더라도 크레딧을받을 수 없습니다.


3
최악의 시나리오에서 여기 에 나열된 가장 빠른 답변보다 훨씬 빠릅니다 .
ChaimG

return next(g, f := next(g, g)) == f(물론 py3.8부터)
Chris_Rands

17

이 작업을 수행하는 두 가지 간단한 방법이 있습니다.

set () 사용

목록을 세트로 변환 할 때 중복 요소가 제거됩니다. 따라서 변환 된 세트의 길이가 1이면 모든 요소가 동일 함을 의미합니다.

len(set(input_list))==1

여기에 예가 있습니다

>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1  # == 3
False
>>> len(set(b))==1  # == 1
True

all () 사용

입력 목록의 첫 번째 요소를 목록의 다른 모든 요소와 비교 (등가)합니다. 모두 동등한 경우 True가 반환되고, 그렇지 않으면 False가 반환됩니다.

all(element==input_list[0] for element in input_list)

여기에 예가 있습니다

>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True

PS 전체 목록이 특정 값과 같은지 확인하는 경우 input_list [0]에 대한 값을 사용할 수 있습니다.


1
런타임에 관심이있는 사람들 len(set(a))의 경우 10,000,000 개의 요소 목록 에서 수행하는 데 0.09 초가 걸리고 수행하는 all데 0.9 초 (10 배 이상)가 걸렸습니다.
Elliptica

2
나는 또한 파이썬 단순이 대답처럼, 성능 점수에 추가 @Elliptica 언급
NickBraunagel

11

이 방법은 len(set(x))==1긴 목록 보다 빠릅니다 (단락 사용).

def constantList(x):
    return x and [x[0]]*len(x) == x

단락을 무시하고 컴퓨터의 설정 솔루션보다 3 배 느립니다. 따라서 목록의 첫 번째 1/3에서 동일하지 않은 요소가 평균적으로 발견되면 평균이 더 빠릅니다.
최대

9

이것은 간단한 방법입니다.

result = mylist and all(mylist[0] == elem for elem in mylist)

이것은 약간 더 복잡하고, 함수 호출 오버 헤드가 발생하지만, 시맨틱은보다 명확하게 설명되어 있습니다.

def all_identical(seq):
    if not seq:
        # empty list is False.
        return False
    first = seq[0]
    return all(first == elem for elem in seq)

를 사용하여 중복 비교를 피할 수 있습니다 for elem in mylist[1:]. 의심 할 여지가 있기 때문에 속도가 크게 향상 elem[0] is elem[0]되므로 통역사가 아마도 그 비교를 매우 빠르게 수행 할 수 있습니다.
Brendan


4

의심 할 여지없이 이것은 "가장 파이썬적인"것입니다.

>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>> 
>>> def testList(list):
...   for item in list[1:]:
...     if item != list[0]:
...       return False
...   return True
... 
>>> testList(falseList)
False
>>> testList(trueList)
True

트릭을 할 것입니다.


1
귀하의 for루프는 더 파이썬로를 만들 수 있습니다 if any(item != list[0] for item in list[1:]): return False정확히 같은 의미로,.
musiphil

4

좀 더 읽기 쉬운 (물론 효율적이지 않은) 것에 관심이 있다면 다음을 시도해보십시오.

def compare_lists(list1, list2):
    if len(list1) != len(list2): # Weed out unequal length lists.
        return False
    for item in list1:
        if item not in list2:
            return False
    return True

a_list_1 = ['apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'apple']

b_list_1 = ['apple', 'orange', 'grape', 'pear']
b_list_2 = ['apple', 'orange', 'banana', 'pear']

c_list_1 = ['apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']

print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False

실제로 한 목록의 모든 요소가 동일한 지 확인하려고합니다. 두 개의 개별 목록이 동일한 경우에는 아닙니다.
최대

4

목록을 세트로 변환 한 다음 세트의 요소 수를 찾으십시오. 결과가 1이면 동일한 요소가 있고 그렇지 않으면 목록의 요소가 동일하지 않습니다.

list1 = [1,1,1]
len(set(list1)) 
>1

list1 = [1,2,3]
len(set(list1)
>3

4

reduce()with를 사용하는 것과 관련하여 lambda. 여기 개인적으로 생각하는 작동 코드가 다른 답변보다 훨씬 좋습니다.

reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))

모든 항목이 같거나 같지 않은 경우 첫 번째 값이 부울 인 튜플을 반환합니다.


코드에 쓰여진 것처럼 작은 실수가 있습니다 (try [1, 2, 2]) : 이전 부울 값을 고려하지 않습니다. 로 교체 x[1] == y하여 해결할 수 있습니다 x[0] and x[1] == y.
SCHOT

3

나는 할 것이다 :

not any((x[i] != x[i+1] for i in range(0, len(x)-1)))

조건을 any찾으면 iterable 검색 을 중지 True합니다.


유일한 인수 인 경우 생성기 표현식 주위에 추가 괄호가 필요하지 않습니다.
ninjagecko

그렇다면 all()왜 사용하지 all(x == seq[0] for x in seq)않습니까? 좀 더 pythonic처럼 보이고 동일하게 수행해야합니다
Chen A.

2
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"

2
def allTheSame(i):
    j = itertools.groupby(i)
    for k in j: break
    for k in j: return False
    return True

"모두"가없는 Python 2.4에서 작동합니다.


1
for k in j: break와 같습니다 next(j). def allTheSame(x): return len(list(itertools.groupby(x))<2)효율성에 신경 쓰지 않으면 할 수도 있습니다 .
ninjagecko

2

지도와 람다를 사용할 수 있습니다

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))

2

또는 diffnumpy 방법을 사용하십시오 .

import numpy as np
def allthesame(l):
    return np.all(np.diff(l)==0)

그리고 전화 :

print(allthesame([1,1,1]))

산출:

True

not np.any(np.diff(l))조금 더 빠를 수 있다고 생각 합니다.
GZ0

2

또는 numpy의 diff 방법을 사용하십시오.

import numpy as np
def allthesame(l):
    return np.unique(l).shape[0]<=1

그리고 전화 :

print(allthesame([1,1,1]))

산출:

진실


이 답변은 작년의 U9-Forward 답변과 동일합니다.
mhwombat

좋은 눈! 나는 동일한 구조 / API를 사용했지만 내 방법은 np.unique 및 shape를 사용합니다. U9의 함수는 np.all () 및 np.diff ()를 사용합니다. 그중 하나를 사용하지 않습니다.
Luis B

1

넌 할 수있어:

reduce(and_, (x==yourList[0] for x in yourList), True)

파이썬으로 연산자를 가져올 수 있다는 것은 상당히 성가신 일입니다 operator.and_. python3부터는 가져 오기가 필요합니다functools.reduce 합니다.

(이 방법은 같지 않은 값을 찾으면 깨지지 않지만 전체 목록을 계속 검토하므로이 방법을 사용하면 안됩니다.이 방법은 완전성에 대한 답변으로 여기에 포함됩니다.)


이것은 단락되지 않습니다. 다른 솔루션보다 선호하는 이유는 무엇입니까?
최대

@max : 당신은 정확하게 그런 이유로하지 않을 것입니다; 나는 완전성을 위해 그것을 포함시켰다. 나는 그것을 언급하기 위해 그것을 편집해야 할 것입니다. 감사합니다.
ninjagecko

1
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]

다음은 단락됩니다 :

all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))

첫 번째 코드는 분명히 틀렸다 : reduce(lambda a,b:a==b, [2,2,2])수율 False... 나는 그것을 편집했지만 더 이상은 그렇지 않다
berdario

@berdario 그렇다면 다른 사람이 쓴 것을 바꾸지 말고 자신의 답변을 작성해야합니다. 이 답변이 잘못되었다고 생각되면 의견을 말하거나 공감할 수 있습니다.
Gorpik

3
모든 사람들이 읽을 수 있도록 잘못된 것을 고치는 것이 낫습니다. 왜 그것이 잘못되었는지 설명하는 주석이 누락되었을 수도 있습니다.
berdario

3
"게시물은 언제 수정해야합니까?" "언제든지 게시물을 더 좋게 만들 수 있다고 생각하며 그렇게하는 경향이 있습니다. 편집을 권장합니다!"
berdario

1

목록을 세트로 변경하십시오. 그런 다음 세트의 크기가 1 인 경우 동일해야합니다.

if len(set(my_list)) == 1:

1

순수한 파이썬 재귀 옵션도 있습니다.

 def checkEqual(lst):
    if len(lst)==2 :
        return lst[0]==lst[1]
    else:
        return lst[0]==lst[1] and checkEqual(lst[1:])

그러나 어떤 이유로 어떤 경우에는 다른 옵션보다 2 배 느립니다. C 언어 정신에서 왔을 때, 나는 이것이 더 빠를 것으로 예상했지만 그렇지 않습니다!

다른 단점은 파이썬에는 재귀 제한이 있으며이 경우 조정해야한다는 것입니다. 예를 들어 this 를 사용 하십시오 .


0

.nunique()목록에서 고유 항목 수를 찾는 데 사용할 수 있습니다 .

def identical_elements(list):
    series = pd.Series(list)
    if series.nunique() == 1: identical = True
    else:  identical = False
    return identical



identical_elements(['a', 'a'])
Out[427]: True

identical_elements(['a', 'b'])
Out[428]: False

0

사용할 수 있습니다 set. 반복적 인 요소를 설정하고 제거합니다. 그런 다음 요소가 1 개 이하인지 확인하십시오.

if len(set(your_list)) <= 1:
    print('all ements are equal')

예:

>>> len(set([5, 5])) <= 1
True
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.