Python memiliki kamus yang diurutkan . Bagaimana dengan set yang dipesan?
collections.Counter
adalah tas Python.
Python memiliki kamus yang diurutkan . Bagaimana dengan set yang dipesan?
collections.Counter
adalah tas Python.
Jawaban:
Ada resep yang diatur (mungkin tautan baru ) resep untuk ini yang dirujuk dari Dokumentasi Python 2 . Ini berjalan pada Py2.6 atau lebih baru dan 3.0 atau lebih baru tanpa modifikasi apa pun. Antarmuka hampir persis sama dengan set normal, kecuali bahwa inisialisasi harus dilakukan dengan daftar.
OrderedSet([1, 2, 3])
Ini adalah MutableSet, jadi tanda tangan untuk .union
tidak cocok dengan yang ditetapkan, tetapi karena menyertakan __or__
sesuatu yang serupa dapat dengan mudah ditambahkan:
@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
dalam kelas yang sama. Yang terakhir akan "menang" dan yang pertama akan gagal ada saat runtime. Ini karena OrderedSet.union
(tanpa parens) harus merujuk ke satu objek.
Kunci-kunci kamus itu unik. Jadi, jika seseorang mengabaikan nilai-nilai dalam kamus yang diurutkan (misalnya dengan menetapkannya None
), maka pada dasarnya ia memiliki kumpulan yang diurutkan.
Pada Python 3.1 ada collections.OrderedDict
. Berikut ini adalah contoh implementasi dari OrderedSet. (Perhatikan bahwa hanya beberapa metode yang perlu didefinisikan atau diganti: collections.OrderedDict
dan collections.MutableSet
lakukan pengangkatan berat.)
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
yang subclass OrderedDict
dan abc.Set
kemudian menentukan __len__
, __iter__
dan __contains__
.
collections
, tetapi sebaliknya saran yang bagus
OrderedSet([1,2,3])
memunculkan TypeError. Bagaimana cara kerja konstruktor? Contoh penggunaan tidak ada.
Jawabannya adalah tidak, tetapi Anda dapat menggunakan collections.OrderedDict
dari pustaka standar Python hanya dengan kunci (dan nilai sebagai None
) untuk tujuan yang sama.
Update : Pada Python 3.7 (dan CPython 3.6), standar dict
ini dijamin untuk mempertahankan ketertiban dan lebih performant dari OrderedDict
. (Namun, untuk kompatibilitas mundur dan terutama keterbacaan, Anda mungkin ingin terus menggunakan OrderedDict
.)
Berikut adalah contoh cara menggunakan dict
set yang dipesan untuk memfilter item duplikat sambil mempertahankan pesanan, sehingga meniru set yang dipesan. Gunakan dict
metode kelas fromkeys()
untuk membuat dict, lalu cukup minta keys()
kembali.
>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']
>>> list(dict.fromkeys(keywords))
['foo', 'bar', 'baz']
dict.fromkeys()
. Tetapi dalam kasus itu, urutan kunci hanya dipertahankan dalam implementasi CPython 3.6+, sehingga OrderedDict
merupakan solusi yang lebih portabel ketika pesanan penting.
keys = (1,2,3,1,2,1)
list(OrderedDict.fromkeys(keys).keys())
-> [1, 2, 3]
, python-3.7. Berhasil.
dict
, set
dalam Python 3.7+ sayangnya tidak mempertahankan ketertiban.
Aku bisa melakukan Anda salah satu lebih baik daripada OrderedSet: Kensington memiliki murni-Python, 2/3-kompatibel IndexedSet
jenis yang tidak hanya set memerintahkan, tetapi juga mendukung pengindeksan (seperti dengan daftar).
Cukup pip install boltons
(atau salin setutils.py
ke basis kode Anda), impor IndexedSet
dan:
>>> 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'
Semuanya unik dan tetap teratur. Pengungkapan penuh: Saya menulis IndexedSet
, tetapi itu juga berarti Anda dapat menggangguku jika ada masalah . :)
Sementara yang lain telah menunjukkan bahwa tidak ada implementasi built-in dari susunan urutan penyisipan diatur dalam Python (belum), saya merasa bahwa pertanyaan ini tidak ada jawaban yang menyatakan apa yang bisa ditemukan di PyPI .
Ada paketnya:
Beberapa implementasi ini didasarkan pada resep yang diposting oleh Raymond Hettinger ke ActiveState yang juga disebutkan dalam jawaban lain di sini.
my_set[5]
)remove(item)
Kedua implementasi memiliki O (1) untuk add(item)
dan __contains__(item)
( item in my_set
).
set.union
tidak berfungsi meskipun, meskipun mewarisi collections.abc.Set
.
Jika Anda menggunakan set yang dipesan untuk mempertahankan pesanan yang diurutkan, pertimbangkan untuk menggunakan implementasi yang diurutkan dari PyPI. The sortedcontainers modul menyediakan SortedSet hanya untuk tujuan ini. Beberapa manfaat: implementasi murni-Python, cepat-sebagai-C, cakupan uji unit 100%, jam pengujian stres.
Menginstal dari PyPI mudah dengan pip:
pip install sortedcontainers
Perhatikan bahwa jika Anda tidak bisa pip install
, cukup tarik ke bawah file sortlist.py dan sortir.py dari repositori open-source .
Setelah diinstal Anda cukup:
from sortedcontainers import SortedSet
help(SortedSet)
Modul wadah yang diurutkan juga mempertahankan perbandingan kinerja dengan beberapa implementasi alternatif.
Untuk komentar yang bertanya tentang tipe data tas Python, ada alternatifnya tipe data SortedList yang dapat digunakan untuk mengimplementasikan tas secara efisien.
SortedSet
kelas di sana mengharuskan anggota untuk dapat dibandingkan dan hashable.
set
dan frozenset
juga membutuhkan elemen yang harus hashable. Batasan yang sebanding adalah tambahan untuk SortedSet
, tetapi juga kendala yang jelas.
Jika Anda sudah menggunakan panda dalam kode Anda, Index
objeknya berperilaku cukup seperti set yang diperintahkan, seperti yang ditunjukkan dalam artikel ini .
Contoh dari artikel:
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)
, tanda minus melakukan pengurangan standar
Sedikit terlambat ke permainan, tapi saya telah menulis sebuah kelas setlist
sebagai bagian dari collections-extended
sepenuhnya mengimplementasikan keduanya Sequence
danSet
>>> 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
Dokumentasi: http://collections-extended.lenzm.net/en/latest/
Tidak ada OrderedSet
di perpustakaan resmi. Saya membuat lembar contekan lengkap dari semua struktur data untuk referensi Anda.
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']
}
The ParallelRegression paket menyediakan setlist () memerintahkan kelas set yang lebih metode-lengkap daripada pilihan berdasarkan resep ActiveState. Ini mendukung semua metode yang tersedia untuk daftar dan kebanyakan jika tidak semua metode tersedia untuk set.
Seperti jawaban lain menyebutkan, untuk python 3.7+, dikt disusun berdasarkan definisi. Alih-alih subklas OrderedDict
kita dapat mensubklas abc.collections.MutableSet
atau typing.MutableSet
menggunakan kunci dict untuk menyimpan nilai-nilai kita.
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__()
Maka cukup:
x = OrderedSet([1, 2, -1, "bar"])
x.add(0)
assert list(x) == [1, 2, -1, "bar", 0]
Saya meletakkan kode ini di perpustakaan kecil , jadi siapa pun bisa pip install
melakukannya.
Untuk banyak tujuan, cukup menelepon saja sudah cukup. Sebagai contoh
>>> 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]
Jika Anda akan menggunakan ini berulang kali, akan ada overhead yang muncul dengan memanggil fungsi yang diurutkan sehingga Anda mungkin ingin menyimpan daftar yang dihasilkan, selama Anda selesai mengubah set. Jika Anda perlu mempertahankan elemen unik dan diurutkan, saya setuju dengan saran untuk menggunakan OrderedDict dari koleksi dengan nilai arbitrer seperti Tidak Ada.
Jadi saya juga punya daftar kecil di mana saya jelas memiliki kemungkinan memperkenalkan nilai-nilai yang tidak unik.
Saya mencari keberadaan daftar unik dari beberapa jenis, tetapi kemudian menyadari bahwa menguji keberadaan elemen sebelum menambahkannya berfungsi dengan baik.
if(not new_element in my_list):
my_list.append(new_element)
Saya tidak tahu apakah ada peringatan untuk pendekatan sederhana ini, tetapi itu memecahkan masalah saya.