순서를 유지하면서 파이썬의 목록에서 중복을 제거하는 내장 기능이 있습니까? 중복 세트를 제거하기 위해 세트를 사용할 수는 있지만 원래 순서는 파괴됩니다. 또한 다음과 같이 나 자신을 굴릴 수 있다는 것을 알고 있습니다.
def uniq(input):
output = []
for x in input:
if x not in output:
output.append(x)
return output
그러나 가능한 경우 내장 또는 더 많은 파이썬 관용구를 사용하고 싶습니다.
관련 질문 : 파이썬에서는 순서를 유지하면서 모든 요소가 고유하도록 목록에서 중복을 제거하는 가장 빠른 알고리즘은 무엇 입니까?
답변
여기 몇 가지 대안이 있습니다. http://www.peterbe.com/plog/uniqifiers-benchmark
가장 빠른 것 :
def f7(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
그냥 전화 seen.add
하는 seen_add
대신에 할당 하는 이유는 무엇 seen.add
입니까? 파이썬은 동적 언어이며, seen.add
각 반복을 해결하는 것은 지역 변수를 해결하는 것보다 비용이 많이 듭니다. seen.add
반복 사이에서 변경되었을 수 있으며 런타임은 그것을 배제 할만 큼 똑똑하지 않습니다. 안전하게 플레이하려면 매번 물체를 확인해야합니다.
동일한 데이터 세트에서이 기능을 많이 사용하려는 경우 다음과 같이 정렬 된 세트를 사용하는 것이 좋습니다. http://code.activestate.com/recipes/528878/
작업 당 O (1) 삽입, 삭제 및 구성원 확인.
(작은 추가 참고 사항 : seen.add()
항상을 반환 None
하므로 or
위의 내용은 논리적 테스트의 필수 부분이 아닌 세트 업데이트를 시도하는 방법으로 만 사용됩니다.)
답변
2016 년 편집
Raymond가 지적했듯이OrderedDict
C로 구현 된 python 3.5 이상에서는 목록 이해 접근 방식이 느립니다 OrderedDict
(실제로 목록이 필요하지 않은 한 입력이 매우 짧은 경우에만). 따라서 3.5+에 가장 적합한 솔루션은 OrderedDict
입니다.
중요 편집 2015
@abarnert가 지적 했듯이 more_itertools
라이브러리 ( pip install more_itertools
)에는 목록 이해에서 읽을 수없는 ( ) 돌연변이unique_everseen
없이이 문제를 해결하기 위해 작성된 함수가 포함되어 있습니다 . 이것은 또한 가장 빠른 솔루션입니다.not seen.add
>>> from more_itertools import unique_everseen
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(unique_everseen(items))
[1, 2, 0, 3]
단 하나의 간단한 라이브러리 가져 오기 및 해킹 없음. 이것은 itertools 레시피의 구현에서 비롯됩니다 unique_everseen
.
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
파이썬 2.7+
에서 허용되는 일반적인 관용구 (작동하지만 속도에 최적화되지 않았으므로 이제는 unique_everseen
)를 사용합니다 collections.OrderedDict
.
런타임 : O (N)
>>> from collections import OrderedDict
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(OrderedDict.fromkeys(items))
[1, 2, 0, 3]
이것은 다음보다 훨씬 멋지게 보입니다.
seen = set()
[x for x in seq if x not in seen and not seen.add(x)]
못생긴 해킹을 사용하지 않습니다 .
not seen.add(x)
이는 set.add
항상 반환되는 인플레 이스 (in-place) 메소드라는 사실에 의존 None
하므로 not None
평가됩니다 True
.
그러나 해킹 솔루션은 동일한 런타임 복잡도 O (N)를 갖지만 원시 속도가 더 빠릅니다.
답변
Python 2.7 에서 원래 순서대로 유지하면서 iterable에서 중복을 제거하는 새로운 방법은 다음과 같습니다.
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Python 3.5 에서 OrderedDict에는 C 구현이 있습니다. 내 타이밍에 따르면 이것이 현재 Python 3.5에 대한 다양한 접근 방식 중 가장 빠르고 가장 짧습니다.
Python 3.6 에서는 일반 dict이 순서가 작고 간결 해졌습니다. (이 기능은 CPython 및 PyPy 용이지만 다른 구현에는 없을 수 있습니다). 이를 통해 주문을 유지하면서 새로운 가장 빠른 중복 제거 방법을 얻을 수 있습니다.
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Python 3.7 에서는 일반 구현이 모든 구현에서 순서대로 보장됩니다. 가장 짧고 빠른 솔루션은 다음과 같습니다.
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
@max에 대한 응답 : 3.6 또는 3.7로 이동하고 OrderedDict 대신 일반 dict를 사용하면 다른 방식으로 성능을 실제로 능가 할 수 없습니다. 사전은 밀도가 높으며 오버 헤드가 거의없는 목록으로 쉽게 변환됩니다. 대상 목록은 len (d)로 사전 크기 조정되어 목록 이해에서 발생하는 모든 크기 조정을 저장합니다. 또한 내부 키 목록은 밀도가 높으므로 포인터를 복사하는 것이 목록 복사와 거의 같습니다.
답변
sequence = ['1', '2', '3', '3', '6', '4', '5', '6']
unique = []
[unique.append(item) for item in sequence if item not in unique]
고유 → ['1', '2', '3', '6', '4', '5']
답변
죽은 말을 걷지 말아라 (이 질문은 매우 오래되었고 이미 많은 정답이 있습니다). 여기에 많은 상황에서 매우 빠르며 사용하기가 쉽지 않은 팬더를 사용하는 솔루션이 있습니다.
import pandas as pd
my_list = [0, 1, 2, 3, 4, 1, 2, 3, 5]
>>> pd.Series(my_list).drop_duplicates().tolist()
# Output:
# [0, 1, 2, 3, 4, 5]
답변
from itertools import groupby
[ key for key,_ in groupby(sortedList)]
목록을 정렬 할 필요조차 없으며 충분한 조건은 동일한 값이 함께 그룹화된다는 것입니다.
편집 : “보존 순서”는 목록이 실제로 정렬되어 있음을 의미한다고 가정했습니다. 그렇지 않은 경우 MizardX의 솔루션이 적합합니다.
커뮤니티 편집 : 그러나 이것은 “중복 연속 요소를 단일 요소로 압축하는”가장 우아한 방법입니다.
답변
주문을 유지하고 싶다면
당신은 이것을 시도 할 수 있습니다 :
list1 = ['b','c','d','b','c','a','a']
list2 = list(set(list1))
list2.sort(key=list1.index)
print list2
또는 이와 유사하게 다음을 수행 할 수 있습니다.
list1 = ['b','c','d','b','c','a','a']
list2 = sorted(set(list1),key=list1.index)
print list2
당신은 또한 이것을 할 수 있습니다 :
list1 = ['b','c','d','b','c','a','a']
list2 = []
for i in list1:
if not i in list2:
list2.append(i)`
print list2
다음과 같이 쓸 수도 있습니다 :
list1 = ['b','c','d','b','c','a','a']
list2 = []
[list2.append(i) for i in list1 if not i in list2]
print list2