[python] 목록을 집합으로 변환하면 요소 순서가 변경됩니다.

최근에 나는 내가 변환하고 때 눈치 listset요소의 순서를 변경하고 문자로 정렬됩니다.

이 예를 고려하십시오.

x=[1,2,20,6,210]
print x
# [1, 2, 20, 6, 210] # the order is same as initial order

set(x)
# set([1, 2, 20, 210, 6]) # in the set(x) output order is sorted

내 질문은-

  1. 왜 이런 일이 발생합니까?
  2. 초기 주문을 잃지 않고 설정 작업 (특히 차액 설정)을 수행하려면 어떻게해야합니까?


답변

  1. A set는 정렬되지 않은 데이터 구조이므로 삽입 순서를 유지하지 않습니다.

  2. 이것은 요구 사항에 따라 다릅니다. 일반 목록이 있고 목록의 순서를 유지하면서 일부 요소 집합을 제거하려는 경우 목록 이해를 사용하여이를 수행 할 수 있습니다.

    >>> a = [1, 2, 20, 6, 210]
    >>> b = set([6, 20, 1])
    >>> [x for x in a if x not in b]
    [2, 210]

    빠른 멤버십 테스트삽입 순서 보존을 모두 지원하는 데이터 구조가 필요한 경우 Python 3.7부터 삽입 순서를 유지하는 Python 사전의 키를 사용할 수 있습니다.

    >>> a = dict.fromkeys([1, 2, 20, 6, 210])
    >>> b = dict.fromkeys([6, 20, 1])
    >>> dict.fromkeys(x for x in a if x not in b)
    {2: None, 210: None}

    b여기서 주문할 필요가 없습니다 set. a 도 사용할 수 있습니다 . 참고 a.keys() - b.keys()A와 차 집합을 반환 set이 삽입 순서를 유지하지 않도록.

    이전 버전의 Python에서는 collections.OrderedDict대신 다음을 사용할 수 있습니다 .

    >>> a = collections.OrderedDict.fromkeys([1, 2, 20, 6, 210])
    >>> b = collections.OrderedDict.fromkeys([6, 20, 1])
    >>> collections.OrderedDict.fromkeys(x for x in a if x not in b)
    OrderedDict([(2, None), (210, None)])

답변

Python 3.6에서는 set()이제 순서를 유지 해야 하지만 Python 2 및 3에 대한 또 다른 솔루션이 있습니다.

>>> x = [1, 2, 20, 6, 210]
>>> sorted(set(x), key=x.index)
[1, 2, 20, 6, 210]


답변

첫 번째 질문에 대한 답으로 집합은 집합 작업에 최적화 된 데이터 구조입니다. 수학적 집합과 마찬가지로 요소의 특정 순서를 적용하거나 유지하지 않습니다. 집합의 추상 개념은 순서를 적용하지 않으므로 구현이 필요하지 않습니다. 목록에서 집합을 만들 때 Python은 집합 작업을 효율적으로 수행 할 수있는 집합에 대해 사용하는 내부 구현의 요구에 따라 요소의 순서를 자유롭게 변경할 수 있습니다.


답변

아래 기능으로 중복 제거 및 순서 유지

def unique(sequence):
    seen = set()
    return [x for x in sequence if not (x in seen or seen.add(x))]

이 링크를 확인


답변

수학에서, 거기 세트명령 세트 (osets).

  • set : 고유 요소의 정렬되지 않은 컨테이너 (구현 됨)
  • oset : 고유 요소의 정렬 된 컨테이너 (NotImplemented)

Python에서는 세트 만 직접 구현됩니다. 일반 사전 키 ( 3.7+ )로 osets를 에뮬레이트 할 수 있습니다 .

주어진

a = [1, 2, 20, 6, 210, 2, 1]
b = {2, 6}

암호

oset = dict.fromkeys(a).keys()
# dict_keys([1, 2, 20, 6, 210])

데모

복제는 제거되고 삽입 순서는 유지됩니다.

list(oset)
# [1, 2, 20, 6, 210]

딕셔너리 키에 대한 세트와 유사한 작업.

oset - b
# {1, 20, 210}

oset | b
# {1, 2, 5, 6, 20, 210}

oset & b
# {2, 6}

oset ^ b
# {1, 5, 20, 210}

세부

참고 : 정렬되지 않은 구조는 정렬 된 요소를 배제하지 않습니다. 오히려 유지 된 순서는 보장되지 않습니다. 예:

assert {1, 2, 3} == {2, 3, 1}                    # sets (order is ignored)

assert [1, 2, 3] != [2, 3, 1]                    # lists (order is guaranteed)

목록다중 집합 (mset)이 두 가지 더 매력적인 수학적 데이터 구조 라는 사실을 알게되면 기뻐할 수 있습니다 .

  • list : 복제를 허용하는 정렬 된 요소 컨테이너 (구현 됨)
  • mset : 복제를 허용하는 요소의 정렬되지 않은 컨테이너 (NotImplemented) *

요약

Container | Ordered | Unique | Implemented
----------|---------|--------|------------
set       |    n    |    y   |     y
oset      |    y    |    y   |     n
list      |    y    |    n   |     y
mset      |    n    |    n   |     n*  

* 다중 집합은 collections.Counter()딕셔너리와 유사한 다중도 (개수) 매핑을 사용하여 간접적으로 에뮬레이션 할 수 있습니다 .


답변

다른 답변에서 알 수 있듯이 세트는 요소 순서를 유지하지 않는 데이터 구조 (및 수학적 개념)입니다.

그러나 세트와 사전의 조합을 사용하면 원하는대로 얻을 수 있습니다. 다음 스 니펫을 사용해보세요.

# save the element order in a dict:
x_dict = dict(x,y for y, x in enumerate(my_list) )
x_set = set(my_list)
#perform desired set operations
...
#retrieve ordered list from the set:
new_list = [None] * len(new_set)
for element in new_set:
   new_list[x_dict[element]] = element


답변

Sven의 답변을 바탕으로 collections.OrderedDict를 사용하여 원하는 것을 달성하고 dict에 더 많은 항목을 추가 할 수 있습니다.

import collections

x=[1,2,20,6,210]
z=collections.OrderedDict.fromkeys(x)
z
OrderedDict([(1, None), (2, None), (20, None), (6, None), (210, None)])

항목을 추가하고 싶지만 여전히 세트처럼 취급하려면 다음을 수행하십시오.

z['nextitem']=None

그리고 dict에서 z.keys ()와 같은 작업을 수행하고 세트를 가져올 수 있습니다.

z.keys()
[1, 2, 20, 6, 210]