파이썬에는 순서가 있습니까?


477

파이썬에는 사전이 있습니다. 주문 세트는 어떻습니까?


18
대화는 어떻습니까? (정렬하지 않고 고유하지 않음)
wim

19
@wim collections.Counter은 Python의 가방입니다.
flornquake

1
무언가가 두 번 추가되면 어떻게됩니까? 입장은 무엇인가?
McKay

2
@McKay는 - 그것은 collections.OrderDict의 동작을 따라한다면 여전히 초기 또한의 위치에있을 것입니다
wojtow

답변:


206

이것에 대한 순서화 된 세트 (가능한 새로운 링크 ) 레시피가 있으며, 이는 Python 2 Documentation 에서 참조됩니다 . Py2.6 이상 및 3.0 이상에서 수정없이 실행됩니다. 인터페이스는 초기화를 목록으로 수행해야한다는 점을 제외하면 일반 세트와 거의 동일합니다.

OrderedSet([1, 2, 3])

이것은 MutableSet이므로에 대한 서명 .union이 세트 의 서명 과 일치하지 않지만 __or__비슷한 것을 포함하기 때문에 쉽게 추가 할 수 있습니다.

@staticmethod
def union(*sets):
    union = OrderedSet()
    union.union(*sets)
    return union

def union(self, *sets):
    for set in sets:
        self |= set

6
문서를 참조하면 공식 답변에 가깝기 때문에 내 답변을 선택했습니다.
Casebash

49
인터페이스는 정확히 일반 설정 객체와 동일하지 않습니다, 많은 중요한 방법 등의 누락 update, union, intersection.
xApple

5
참고로, 나는 것으로 나타났습니다 약간 수정 된 버전이 답변에 인용 된 레시피가PyPi에 추가 "명령 세트"로
제프리 힝

7
union같은 클래스에서 두 가지 메서드를 모두 호출 할 수는 없습니다 . 마지막은 "승리"하고 첫 번째는 런타임에 존재하지 않습니다. 이는 OrderedSet.union(parens 없음) 단일 객체 를 참조해야 하기 때문 입니다.
Kevin

3
같은 레시피를 기반으로하지만, 사이 썬에서 구현된다 "orderedset"패키지도 있습니다 - pypi.python.org/pypi/orderedset은 .
mbdevpl

149

정렬 된 집합은 기능적으로 정렬 된 사전의 특수한 경우입니다.

사전의 키는 고유합니다. 따라서 정렬 된 사전에서 값을 무시하면 (예 : 값을 할당하여 None) 본질적으로 정렬 된 세트를 갖습니다.

파이썬 3.1으로 있다 collections.OrderedDict. 다음은 OrderedSet의 구현 예입니다. (단 몇 가지 방법을 정의 또는 오버라이드 (override) 할 필요가 있습니다 : collections.OrderedDictcollections.MutableSet. 무거운 리프팅을 할)

import collections

class OrderedSet(collections.OrderedDict, collections.MutableSet):

    def update(self, *args, **kwargs):
        if kwargs:
            raise TypeError("update() takes no keyword arguments")

        for s in args:
            for e in s:
                 self.add(e)

    def add(self, elem):
        self[elem] = None

    def discard(self, elem):
        self.pop(elem, None)

    def __le__(self, other):
        return all(e in other for e in self)

    def __lt__(self, other):
        return self <= other and self != other

    def __ge__(self, other):
        return all(e in self for e in other)

    def __gt__(self, other):
        return self >= other and self != other

    def __repr__(self):
        return 'OrderedSet([%s])' % (', '.join(map(repr, self.keys())))

    def __str__(self):
        return '{%s}' % (', '.join(map(repr, self.keys())))

    difference = __sub__ 
    difference_update = __isub__
    intersection = __and__
    intersection_update = __iand__
    issubset = __le__
    issuperset = __ge__
    symmetric_difference = __xor__
    symmetric_difference_update = __ixor__
    union = __or__

1
@Casebash : 예, 하나의 클래스를 정의 할 수 OrderedSet있는 서브 클래스 OrderedDictabc.Set다음, 정의 __len__, __iter__그리고 __contains__.
Stephan202

1
@ collections
Stephan202

4
이것은 사실이지만 결과적으로 낭비되는 공간이 많으므로 성능이 저하됩니다.
Daniel Kats

3
추가; Pythons 2.7에서도 OrdedDict를 사용할 수 있습니다.
Nurbldoff

2
그렇게하면 OrderedSet([1,2,3])TypeError가 발생합니다. 생성자는 어떻게 작동합니까? 사용 예가 없습니다.
xApple

90

대답은 아니오이지만 동일한 목적 collections.OrderedDict으로 키 (및 값 None) 만으로 Python 표준 라이브러리에서 사용할 수 있습니다 .

업데이트 : Python 3.7 (및 CPython 3.6)부터 표준 dict순서를 유지하도록 보장되며 보다 성능이 뛰어납니다 OrderedDict. 그러나 이전 버전과의 호환성 및 특히 가독성을 위해 계속해서 사용하는 것이 OrderedDict좋습니다.

다음 dict은 주문을 유지하면서 중복 항목을 필터링하여 주문 세트를 에뮬레이트하는 주문 세트 로 사용하는 방법의 예입니다 . 사용 dict클래스 메소드를 fromkeys()다음 단순히 요청하는 딕셔너리를 만드는 keys()다시.

>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']

>>> list(dict.fromkeys(keywords))
['foo', 'bar', 'baz']

4
아마도 이것도 바닐라와 함께 작동한다는 것을 언급 할 가치가 dict.fromkeys()있습니다. 그러나이 경우 키 순서는 CPython 3.6+ 구현에서만 유지되므로 OrderedDict순서가 중요 할 때보다 이식 가능한 솔루션입니다.
jez December

1
값이 문자열이 아닌 경우 작동하지 않습니다
앤워 후세인

4
@AnwarHossain- keys = (1,2,3,1,2,1) list(OrderedDict.fromkeys(keys).keys())> [1, 2, 3], python-3.7. 효과가있다.
raratiru

1
Python 3.7 이상에서 Set도 순서를 유지한다고 추론 할 수 있습니까?
user474491

2
@ user474491 달리 dict, set파이썬 3.7+ 불행하게도 순서를 유지하지 않습니다.
cz

39

나는 당신에게 OrderedSet보다 하나 더 잘 할 수 있습니다 : boltons는 순서가 지정된 세트 일뿐 만 아니라 색인을 지원 하는 순수한 파이썬, 2/3 호환 IndexedSet유형 을 가지고 있습니다 (목록과 마찬가지로).

간단하게 pip install boltons(또는 setutils.py코드베이스에 복사 ) 및를 가져옵니다 IndexedSet.

>>> from boltons.setutils import IndexedSet
>>> x = IndexedSet(list(range(4)) + list(range(8)))
>>> x
IndexedSet([0, 1, 2, 3, 4, 5, 6, 7])
>>> x - set(range(2))
IndexedSet([2, 3, 4, 5, 6, 7])
>>> x[-1]
7
>>> fcr = IndexedSet('freecreditreport.com')
>>> ''.join(fcr[:fcr.index('.')])
'frecditpo'

모든 것이 독특하고 순서대로 유지됩니다. 전체 공개 : 나는 쓴 IndexedSet,하지만 그 또한 의미 문제가 있는지 할 수 있습니다에게 버그 나 . :)


39

PyPI 구현

다른 사람들은 파이썬 (아직)에 삽입 순서 보존 세트의 내장 구현이 없다고 지적했지만이 질문에는 PyPI 에서 무엇을 찾을 수 있는지에 대한 답변이 누락되었다고 생각합니다 .

패키지가 있습니다 :

이러한 구현 중 일부는 Raymond Hettinger가 ActiveState에 게시 한 레시피를 기반으로하며 여기에 다른 답변에서도 언급되어 있습니다.

약간의 차이

  • 주문 세트 (버전 1.1)
    • 장점 : 인덱스에 의해 조회를 위해 O (1) (예 my_set[5])
  • oset (버전 0.1.3)
    • 장점 : O (1) remove(item)
    • 단점 : 인덱스 별 조회의 경우 분명히 O (n)

모두 구현은 O (1)에 대한이 add(item)__contains__(item)( item in my_set)를.


2
새로운 컨텐더는 collections_extended.setlist 입니다. set.union상속하는 경우에도 같은 기능은 작동하지 않습니다 collections.abc.Set.
timdiels

3
OrderedSet현재 지원remove
warvariuc

17

정렬 된 순서를 유지하기 위해 정렬 된 집합을 사용하는 경우 PyPI에서 정렬 된 집합 구현을 사용해보십시오. sortedcontainers의 모듈은 제공 SortedSet의를 바로이 목적을 위해. 몇 가지 장점 : 순수 Python, 빠른 C 구현, 100 % 단위 테스트 적용 범위, 스트레스 테스트 시간.

pip를 사용하면 PyPI에서 쉽게 설치할 수 있습니다.

pip install sortedcontainers

할 수없는 경우 오픈 소스 리포지토리pip install 에서 sortedlist.py 및 sortedset.py 파일을 풀다운하면 됩니다.

설치 한 후에는 간단하게 다음을 수행 할 수 있습니다.

from sortedcontainers import SortedSet
help(SortedSet)

sortedcontainers 모듈은 여러 대체 구현과 성능 비교 를 유지합니다 .

Python의 bag 데이터 유형에 대한 질문 에는 bag을 효율적으로 구현하는 데 사용할 수 있는 SortedList 데이터 유형이 있습니다.


점을 유의 SortedSet클래스 비교 및 해쉬로 구성원이 필요합니다.
gsnedders

4
내장 매크로를 @gsnedders set하고 frozenset또한 해쉬 될 요소가 필요합니다. 비교할 수있는 제약 조건은에 대한 추가 사항 SortedSet이지만 명백한 제약 조건이기도합니다.
gotgenes 2012 년

2
이름에서 알 수 있듯이 순서는 유지되지 않습니다. 더 나아지는 것은 sorted (set ([sequence]))에 지나지 않습니다.
ldmtwo

@ldmtwo 나는 당신이 어느 것을 언급하고 있는지 확실하지 않지만 명확하게 정리하기 위해 정렬 된 컨테이너의 일부 인 SortedSet 은 정렬 된 순서를 유지합니다.
GrantJ

2
@GrantJ- 삽입 순서를 유지하는지 또는 정렬 순서를 유지하는지의 차이 입니다. 다른 답변의 대부분은 게재 신청서와 관련이 있습니다. 나는 당신이 이미 당신의 첫 문장을 기초로 이것을 알고 있다고 생각하지만, 아마도 ldmtwo가 말한 것일 것입니다.
Justin

8

코드에서 이미 팬더를 사용중인 경우이 기사에Index 표시된 것처럼 해당 객체는 정렬 된 세트처럼 동작 합니다.

기사의 예 :

indA = pd.Index([1, 3, 5, 7, 9])
indB = pd.Index([2, 3, 5, 7, 11])

indA & indB  # intersection
indA | indB  # union
indA - indB  # difference
indA ^ indB  # symmetric difference

이 답변에 예를 포함시킬 수 있습니까? 시간이 지나면 링크가 끊어지는 경향이 있습니다.
Alechan

1
집합 간의 차이를 위해서는 실제로를 사용해야 indA.difference(indB)합니다. 빼기 기호는 표준 빼기를 수행합니다
gg349

7

후반 게임에 조금씩, 그러나 나는 클래스를 작성했습니다 setlist의 일환으로 collections-extended이 완벽하게 구현 모두 SequenceSet

>>> from collections_extended import setlist
>>> sl = setlist('abracadabra')
>>> sl
setlist(('a', 'b', 'r', 'c', 'd'))
>>> sl[3]
'c'
>>> sl[-1]
'd'
>>> 'r' in sl  # testing for inclusion is fast
True
>>> sl.index('d')  # so is finding the index of an element
4
>>> sl.insert(1, 'd')  # inserting an element already in raises a ValueError
ValueError
>>> sl.index('d')
4

GitHub : https://github.com/mlenzen/collections-extended

설명서 : http://collections-extended.lenzm.net/en/latest/

PyPI : https://pypi.python.org/pypi/collections-extended


7

OrderedSet공식 도서관 에는 없습니다 . 나는 당신의 참고를 위해 모든 데이터 구조의 철저한 치트 시트를 만듭니다.

DataStructure = {
    'Collections': {
        'Map': [
            ('dict', 'OrderDict', 'defaultdict'),
            ('chainmap', 'types.MappingProxyType')
        ],
        'Set': [('set', 'frozenset'), {'multiset': 'collection.Counter'}]
    },
    'Sequence': {
        'Basic': ['list', 'tuple', 'iterator']
    },
    'Algorithm': {
        'Priority': ['heapq', 'queue.PriorityQueue'],
        'Queue': ['queue.Queue', 'multiprocessing.Queue'],
        'Stack': ['collection.deque', 'queue.LifeQueue']
        },
    'text_sequence': ['str', 'byte', 'bytearray']
}

3

ParallelRegression의 패키지는 제공 연주곡 ()를 더 메소드 완료 ActiveState의 조리법에 따라 옵션보다 세트 클래스를 명령했다. 리스트에 사용 가능한 모든 메소드를 지원하며, 모든 메소드가 세트에 사용 가능한 것은 아닙니다.


2

다른 답변에서 언급했듯이 python 3.7 이상에서는 dict이 정의에 따라 정렬됩니다. 서브 클래 싱 대신 서브 클래스 OrderedDict를 만들 abc.collections.MutableSet거나 typing.MutableSetdict의 키를 사용하여 값을 저장할 수 있습니다.

class OrderedSet(typing.MutableSet[T]):
    """A set that preserves insertion order by internally using a dict."""

    def __init__(self, iterable: t.Iterator[T]):
        self._d = dict.fromkeys(iterable)

    def add(self, x: T) -> None:
        self._d[x] = None

    def discard(self, x: T) -> None:
        self._d.pop(x)

    def __contains__(self, x: object) -> bool:
        return self._d.__contains__(x)

    def __len__(self) -> int:
        return self._d.__len__()

    def __iter__(self) -> t.Iterator[T]:
        return self._d.__iter__()

그런 다음 :

x = OrderedSet([1, 2, -1, "bar"])
x.add(0)
assert list(x) == [1, 2, -1, "bar", 0]

이 코드를 작은 라이브러리에 넣었 으므로 누구나 사용할 수 있습니다 pip install.


-4

많은 목적을 위해 단순히 소트를 부르는 것으로 충분합니다. 예를 들어

>>> s = set([0, 1, 2, 99, 4, 40, 3, 20, 24, 100, 60])
>>> sorted(s)
[0, 1, 2, 3, 4, 20, 24, 40, 60, 99, 100]

이것을 반복해서 사용하려는 경우 정렬 된 함수를 호출하면 오버 헤드가 발생하므로 세트 변경을 완료 한 경우 결과 목록을 저장할 수 있습니다. 고유 한 요소를 유지 관리하고 정렬 해야하는 경우 None과 같은 임의의 값을 가진 컬렉션에서 OrderedDict를 사용하라는 제안에 동의합니다.


43
OrderedSet의 목적은 세트에 추가 된 순서대로 항목을 가져올 수 있도록하는 것입니다. 예를 들어 SortedSet ...이라고 할 수 있습니다.
정기 유지 보수

-4

그래서 나는 또한 고유하지 않은 값을 도입 할 가능성이있는 작은 목록을 가지고있었습니다.

나는 일종의 고유 한 목록이 있는지 검색했지만 요소를 추가하기 전에 요소의 존재를 테스트하면 잘 작동한다는 것을 깨달았습니다.

if(not new_element in my_list):
    my_list.append(new_element)

이 간단한 접근 방식에주의 사항이 있는지 모르겠지만 문제를 해결합니다.


이 방법의 주요 문제는 O (n)에서 런을 추가하는 것입니다. 큰 목록을 사용하면 속도가 느려집니다. 파이썬의 내장 세트는 요소를 더 빠르게 추가하는 데 매우 능숙합니다. 그러나 간단한 사용 사례의 경우 확실히 작동합니다!
Draconis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.