Python có một từ điển được đặt hàng . Một bộ được đặt hàng thì sao?
collections.Counter
là túi của Python.
Python có một từ điển được đặt hàng . Một bộ được đặt hàng thì sao?
collections.Counter
là túi của Python.
Câu trả lời:
Có một công thức được đặt hàng ( liên kết mới có thể ) cho cái này được tham chiếu từ Tài liệu Python 2 . Điều này chạy trên Py2.6 trở lên và 3.0 trở lên mà không có bất kỳ sửa đổi nào. Giao diện gần giống hệt như một bộ bình thường, ngoại trừ việc khởi tạo nên được thực hiện với một danh sách.
OrderedSet([1, 2, 3])
Đây là Mutableset, vì vậy chữ ký .union
không khớp với tập hợp, nhưng vì nó bao gồm __or__
một cái gì đó tương tự có thể dễ dàng được thêm vào:
@staticmethod
def union(*sets):
union = OrderedSet()
union.union(*sets)
return union
def union(self, *sets):
for set in sets:
self |= set
update
, union
, intersection
.
union
trong cùng một lớp. Người cuối cùng sẽ "chiến thắng" và người đầu tiên sẽ không tồn tại trong thời gian chạy. Điều này là do OrderedSet.union
(không có parens) phải tham chiếu đến một đối tượng duy nhất .
Các khóa của một từ điển là duy nhất. Do đó, nếu người ta bỏ qua các giá trị trong một từ điển có thứ tự (ví dụ: bằng cách gán chúng None
), thì về cơ bản, nó có một tập hợp có thứ tự.
Như Python 3.1 có collections.OrderedDict
. Sau đây là một ví dụ triển khai của Orderedset. (Lưu ý rằng chỉ có một vài phương thức cần được xác định hoặc ghi đè: collections.OrderedDict
và collections.MutableSet
thực hiện việc nâng vật nặng.)
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__
OrderedSet
mà lớp con OrderedDict
và abc.Set
và sau đó xác định __len__
, __iter__
và __contains__
.
collections
, nhưng nếu không thì là một gợi ý hay
OrderedSet([1,2,3])
tăng một TypeError. Làm thế nào để các nhà xây dựng thậm chí làm việc? Thiếu ví dụ sử dụng.
Câu trả lời là không, nhưng bạn có thể sử dụng collections.OrderedDict
từ thư viện chuẩn Python chỉ với các khóa (và các giá trị như None
) cho cùng một mục đích.
Cập nhật : Kể từ Python 3.7 (và CPython 3.6), tiêu chuẩn dict
được đảm bảo để duy trì trật tự và có hiệu suất cao hơn OrderedDict
. (Tuy nhiên, để tương thích ngược và đặc biệt là khả năng đọc, bạn có thể muốn tiếp tục sử dụng OrderedDict
.)
Dưới đây là một ví dụ về cách sử dụng dict
như một bộ được đặt hàng để lọc ra các mục trùng lặp trong khi duy trì trật tự, từ đó mô phỏng một bộ được đặt hàng. Sử dụng dict
phương thức lớp fromkeys()
để tạo ra một dict, sau đó chỉ cần yêu cầu mặt keys()
sau.
>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']
>>> list(dict.fromkeys(keywords))
['foo', 'bar', 'baz']
dict.fromkeys()
. Nhưng trong trường hợp đó, thứ tự chính chỉ được bảo toàn trong các triển khai CPython 3.6+, vì vậy đây OrderedDict
là một giải pháp di động hơn khi đơn hàng có vấn đề.
keys = (1,2,3,1,2,1)
list(OrderedDict.fromkeys(keys).keys())
-> [1, 2, 3]
, trăn-3.7. Nó hoạt động.
dict
, set
trong Python 3.7+ không may không giữ được thứ tự.
Tôi có thể làm cho bạn một tốt hơn so với một OrderedSet: boltons có một tinh khiết-Python, 2/3 tương thích IndexedSet
kiểu đó là không chỉ là một tập có thứ tự, mà còn hỗ trợ lập chỉ mục (như với danh sách).
Chỉ cần pip install boltons
(hoặc sao chép setutils.py
vào cơ sở mã của bạn), nhập IndexedSet
và:
>>> 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'
Tất cả mọi thứ là duy nhất và được giữ lại theo thứ tự. Tiết lộ đầy đủ: Tôi đã viết IndexedSet
, nhưng điều đó cũng có nghĩa là bạn có thể lỗi tôi nếu có bất kỳ vấn đề nào . :)
Trong khi những người khác đã chỉ ra rằng không có triển khai tích hợp nào trong bộ bảo quản thứ tự chèn trong Python (tôi), tôi cảm thấy rằng câu hỏi này thiếu một câu trả lời trong đó nêu lên những gì cần tìm thấy trên PyPI .
Có các gói:
Một số trong những triển khai này dựa trên công thức được đăng bởi Raymond Hettinger lên ActiveState , cũng được đề cập trong các câu trả lời khác ở đây.
my_set[5]
)remove(item)
Cả hai triển khai đều có O (1) cho add(item)
và __contains__(item)
( item in my_set
).
set.union
không hoạt động trên đó mặc dù nó kế thừa collections.abc.Set
.
OrderedSet
hiện hỗ trợremove
Nếu bạn đang sử dụng bộ được đặt hàng để duy trì thứ tự được sắp xếp, hãy xem xét sử dụng triển khai bộ được sắp xếp từ PyPI. Các sortedcontainers mô-đun cung cấp một SortedSet chỉ cho mục đích này. Một số lợi ích: Python thuần túy, triển khai nhanh như C, phạm vi kiểm tra đơn vị 100%, kiểm tra căng thẳng hàng giờ.
Cài đặt từ PyPI rất dễ dàng với pip:
pip install sortedcontainers
Lưu ý rằng nếu bạn không thể pip install
, chỉ cần kéo xuống các tệp sortlist.py và sortset.py từ kho lưu trữ nguồn mở .
Sau khi cài đặt, bạn có thể chỉ cần:
from sortedcontainers import SortedSet
help(SortedSet)
Mô-đun sortcontainers cũng duy trì so sánh hiệu suất với một số triển khai thay thế.
Đối với nhận xét được hỏi về loại dữ liệu túi của Python, thay vào đó là loại dữ liệu Sắp xếp Danh sách có thể được sử dụng để triển khai hiệu quả túi.
SortedSet
lớp ở đó yêu cầu các thành viên phải tương đương và có thể băm.
set
và frozenset
cũng yêu cầu các yếu tố có thể băm được. Ràng buộc tương đương là sự bổ sung cho SortedSet
, nhưng nó cũng là một ràng buộc rõ ràng.
Trong trường hợp bạn đã sử dụng gấu trúc trong mã của mình, Index
đối tượng của nó hoạt động khá giống một bộ được đặt hàng, như trong bài viết này .
Ví dụ từ bài viết:
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
indA.difference(indB)
, dấu trừ thực hiện phép trừ tiêu chuẩn
Hơi muộn một chút với trò chơi, nhưng tôi đã viết một lớp setlist
như một phần của collections-extended
việc thực hiện đầy đủ cả hai Sequence
vàSet
>>> 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-extends
Không có OrderedSet
trong thư viện chính thức. Tôi tạo ra một bộ quần áo đầy đủ tất cả các cấu trúc dữ liệu để bạn tham khảo.
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']
}
Các ParallelRegression gói cung cấp một setlist () ra lệnh cho bộ lớp đó là phương pháp hoàn tất hơn các tùy chọn dựa trên công thức ActiveState. Nó hỗ trợ tất cả các phương thức có sẵn cho danh sách và hầu hết nếu không phải tất cả các phương thức có sẵn cho các bộ.
Như các câu trả lời khác đề cập, như đối với python 3.7+, dict được sắp xếp theo định nghĩa. Thay vì phân lớp, OrderedDict
chúng ta có thể phân lớp abc.collections.MutableSet
hoặc typing.MutableSet
sử dụng các khóa của dict để lưu trữ các giá trị của chúng ta.
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__()
Sau đó, chỉ cần:
x = OrderedSet([1, 2, -1, "bar"])
x.add(0)
assert list(x) == [1, 2, -1, "bar", 0]
Tôi đặt mã này trong một thư viện nhỏ , vì vậy bất cứ ai cũng có thể chỉ cần pip install
nó.
Đối với nhiều mục đích chỉ đơn giản là gọi sắp xếp sẽ đủ. Ví dụ
>>> 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]
Nếu bạn định sử dụng điều này nhiều lần, sẽ có chi phí phát sinh bằng cách gọi hàm được sắp xếp để bạn có thể muốn lưu danh sách kết quả, miễn là bạn đã hoàn tất việc thay đổi tập hợp. Nếu bạn cần duy trì các yếu tố duy nhất và được sắp xếp, tôi đồng ý với đề xuất sử dụng OrderedDict từ các bộ sưu tập có giá trị tùy ý như Không có.
Vì vậy, tôi cũng có một danh sách nhỏ nơi tôi rõ ràng có khả năng giới thiệu các giá trị không độc đáo.
Tôi đã tìm kiếm sự tồn tại của một danh sách duy nhất của một số loại, nhưng sau đó nhận ra rằng việc kiểm tra sự tồn tại của phần tử trước khi thêm nó hoạt động tốt.
if(not new_element in my_list):
my_list.append(new_element)
Tôi không biết có cách nào để tiếp cận phương pháp đơn giản này không, nhưng nó giải quyết được vấn đề của tôi.