Python'un sıralı bir seti var mı?


477

Python'un sıralı bir sözlüğü var . Sipariş edilen sete ne dersiniz?


18
Ya sohbet, bir çanta dolusu şey? (sırasız ve benzersiz olmayan)
wim

19
@ wim collections.CounterPython'un çantası.
flornquake

1
Ya bir şey iki kez eklenirse? Pozisyon ne olmalı?
McKay

2
@McKay - koleksiyonların davranışlarını takip edecek olsaydı.OrderDict hala ilk ekleme pozisyonunda olacaktı
wojtow

Yanıtlar:


206

Bunun için Python 2 Dokümantasyonundan atıfta bulunulan sıralı bir set (olası yeni bağlantı ) tarifi vardır . Bu, herhangi bir değişiklik yapılmadan Py2.6 veya üstü ve 3.0 veya üstü üzerinde çalışır. Başlatma işleminin bir liste ile yapılması dışında arayüz normal bir setle neredeyse tamamen aynıdır.

OrderedSet([1, 2, 3])

Bu bir MutableSet, bu nedenle imzası kümeninkiyle eşleşmiyor, .unionancak __or__benzer bir şey içerdiğinden kolayca eklenebilir:

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

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

6
Kendi cevabımı seçtim, çünkü belgelerdeki referans bunu resmi bir cevaba yaklaştırıyor
Casebash

49
Arayüz Tam olarak normal seti nesnesi olarak aynı değildir, birçok temel yöntemler gibi eksik update, union, intersection.
xApple

5
Bilginize, ben bir fark biraz değiştirilmiş versiyonu arasında bu cevap belirtilen reçete edilmiş PyPi eklenen "sıralı-kümesi" olarak
Geoffrey Hing

7
Her ikisinin unionde aynı sınıfta çağırılmasına izin verilmediğinden eminim . Sonuncusu "kazanır" ve birincisi çalışma zamanında var olmaz. Çünkü OrderedSet.union(parens yok) tek bir nesneye gönderme yapmak zorundadır .
Kevin

3
Aynı tarife dayanan ancak Cython - pypi.python.org/pypi/orderedset içinde uygulanan "düzenli set" paketi de vardır .
mbdevpl

149

Sıralı bir set işlevsel olarak sıralı bir sözlüğün özel bir halidir.

Bir sözlüğün anahtarları benzersizdir. Dolayısıyla, biri sıralı bir sözlükteki değerleri göz ardı ederse (örneğin atayarak None), o zaman esasen sıralı bir kümeye sahiptir.

Python 3.1 itibariyle yoktur collections.OrderedDict. Aşağıda bir OrderedSet uygulamasının örneği yer almaktadır. (Sadece birkaç yöntemin tanımlanması veya geçersiz kılınması gerektiğini unutmayın: collections.OrderedDictve collections.MutableSetağır kaldırmayı yapın.)

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: evet, tek bir sınıf tanımlamak isteyebilirsiniz OrderedSethangi alt sınıfları OrderedDictve abc.Setardından tanımlamak __len__, __iter__ve __contains__.
Stephan202

1
@ Stephan202: Ne yazık ki, koleksiyon ABC'leri yaşıyor collections, ama aksi halde iyi bir öneri
u0b34a0f6ae

4
Bu doğrudur, ancak sonuç olarak düşük performansa yol açan çok fazla boşa alanınız var.
Daniel Kats

3
Bir ekleme; OrderDict ayrıca python 2.7'de de mevcuttur.
Nurbldoff

2
Bunu yapmak OrderedSet([1,2,3])bir TypeError hatası yükseltir. Yapıcı nasıl çalışır? Eksik kullanım örneği.
xApple

90

Cevap hayırdır, ancak collections.OrderedDictPython standart kütüphanesinden Noneaynı amaç için sadece anahtarları (ve değerleri ) kullanabilirsiniz.

Güncelleme : Python 3.7 (ve CPython 3.6) itibariyle, standart siparişi koruyacakdict şekilde garanti edilir ve daha fazla performans gösterir OrderedDict. (Ancak geriye dönük uyumluluk ve özellikle okunabilirlik için kullanmaya devam etmek isteyebilirsiniz OrderedDict.)

Aşağıda dict, sipariş korunurken yinelenen öğeleri filtrelemek ve böylece sıralı bir seti taklit etmek için sıralı bir set olarak nasıl kullanılacağına dair bir örnek verilmiştir . Bir diksiyon oluşturmak için dictclass yöntemini kullanın fromkeys(), sonra sadece keys()arka istemek .

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

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

4
Belki de bunun vanilya ile de (daha hızlı) çalıştığını belirtmek gerekir dict.fromkeys(). Ancak bu durumda, anahtar sipariş yalnızca CPython 3.6+ uygulamalarında korunur, bu nedenle OrderedDictsipariş önemli olduğunda daha taşınabilir bir çözümdür.
jez

1
değerler dize değilse çalışmaz
Anwar Hossain

4
@AnwarHossain keys = (1,2,3,1,2,1) list(OrderedDict.fromkeys(keys).keys())-> [1, 2, 3], python-3.7. İşe yarıyor.
raratiru

1
Set in Python 3.7+ koru siparişini de çıkarabilir miyiz?
user474491

2
@ user474491 Aksine dict, setPython 3.7+ 'de maalesef düzeni korumaz.
cz

39

Size bir OrderedSet daha iyi yapabilirim: boltons saf-Python,IndexedSet sadece sıralı bir set değil, aynı zamanda indekslemeyi (listelerde olduğu gibi) destekleyen 2/3 uyumlu bir türe sahiptir.

Basitçe pip install boltons(veya setutils.pykod tabanınıza kopyalayın ) IndexedSetve:

>>> 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'

Her şey benzersizdir ve sırayla korunur. Tam açıklama: Ben yazdım IndexedSet, ama aynı zamanda herhangi bir sorun varsa beni rahatsız edebileceğiniz anlamına gelir . :)


39

PyPI üzerinde uygulamalar

Diğerleri, Python'da (henüz) bir yerleştirme siparişi korumasının yerleşik bir uygulaması olmadığını belirtmiş olsa da, bu sorunun PyPI'de ne bulunacağını belirten bir cevabı eksik olduğunu hissediyorum .

Paketler var:

Bu uygulamalardan bazıları, Raymond Hettinger tarafından ActiveState'e gönderilen ve buradaki diğer cevaplarda da belirtilen tarife dayanmaktadır .

Bazı farklılıklar

  • sıralı set (sürüm 1.1)
    • avantajı: indeksi aramalar için O (1) (örneğin my_set[5])
  • oset (sürüm 0.1.3)
    • avantajı: O (1) için remove(item)
    • dezavantaj: Görünüşe göre endekse göre aramalar için O (n)

Her iki uygulamada add(item)ve __contains__(item)( item in my_set) için O (1 ) vardır.


2
Yeni bir yarışmacı collections_extended.setlist . Gibi işlevleri set.unionmiras olsa da üzerinde çalışmıyor collections.abc.Set.
timdiels

3
OrderedSetşimdi destekliyorremove
warvariuc

17

Sıralı seti korumak için sıralı seti kullanıyorsanız, PyPI'den sıralı set uygulaması kullanmayı düşünün. Sortedcontainers modülü sağlar SortedSet sadece bu amaç için. Bazı faydaları: saf Python, C kadar hızlı uygulamalar,% 100 birim test kapsamı, saatlerce stres testi.

Pip ile PyPI'den kurulum kolaydır:

pip install sortedcontainers

Not açamıyorsa pip install, basitçe dan sortedlist.py ve sortedset.py dosyaları aşağı çekmek açık kaynaklı depo .

Kurulduktan sonra şunları yapabilirsiniz:

from sortedcontainers import SortedSet
help(SortedSet)

Sortcontainers modülü ayrıca çeşitli alternatif uygulamalarla bir performans karşılaştırması yapar .

Python'un torba veri türü hakkında soru soran yorum için alternatif olarak bir torbayı verimli bir şekilde uygulamak için kullanılabilecek bir SortedList veri türü vardır.


Not SortedSetsınıf karşılaştırılabilir ve hashable olmasını üyelerini orada gerektirir.
gsnedders

4
@gsnedders Yerleşikler setve frozensetayrıca elemanların yıkanabilir olmasını gerektirir. Karşılaştırılabilir kısıtlama eklentidir SortedSet, ancak aynı zamanda bariz bir kısıtlamadır.
15:15

2
Adından da anlaşılacağı gibi, bu düzeni korumaz. Sıralanmış (set ([sıra])) dışında başka bir şey değil mi?
ldmtwo

@ ldmtwo Ne kastettiğinizden emin değilim, ancak açık olmak gerekirse , Sıralı Kapsayıcıların bir parçası olarak SortedSet sıralı sıralamayı koruyor.
GrantJ

2
@GrantJ - Kampanya siparişini veya sıralama düzenini muhafaza edip etmediği arasındaki farktır . Diğer cevapların çoğu kampanya siparişiyle ilgilidir. Sanırım ilk cümlenize dayanarak bunun farkındasınız, ama muhtemelen ldmtwo'nun söylediği şey bu.
Justin

8

Kodunuzda zaten panda kullanıyorsanız, Indexnesnesi bu makalede gösterildiği gibi sıralı bir küme gibi davranır .

Makaleden örnekler:

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

Bu cevaba bir örnek ekleyebilir misiniz? Bağlantılar bir süre sonra kopma eğilimindedir.
Alechan

1
setler arasındaki fark için, aslında kullanmanız gerekir indA.difference(indB), eksi işareti standart çıkarma yapar
gg349

7

Geç oyuna Biraz ama ben bir sınıf yazdım setlistbir parçası olarak collections-extendedo tamamen uygular hem SequenceveSet

>>> 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

Belgeler: http://collections-extended.lenzm.net/en/latest/

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


7

Hiçbir Orada OrderedSetresmi kütüphanede. Referansınız için tüm veri yapısının kapsamlı bir hile sayfasını hazırladım.

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 paketi içerir setlist () metodu daha tamamlama ActiveState tarifi göre seçeneklerine göre ayar sınıfı vermiştir. Listeler için kullanılabilir tüm yöntemleri ve kümeler için mevcut olmasa bile çoğu yöntemi destekler.


2

Diğer cevapların belirttiği gibi, python 3.7+ için, söz tanım gereği sıralanmıştır. Alt sınıflandırma yerine değerlerimizi saklamak için OrderedDictalt sınıfları kullanabilir abc.collections.MutableSetveya typing.MutableSetdikt tuşlarını kullanabiliriz.

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__()

O zaman sadece:

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

Bu kodu küçük bir kütüphaneye koydum , böylece herkes sadece yapabilir pip install.


-4

Birçok amaç için sıralı çağırmak yeterli olacaktır. Örneğin

>>> 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]

Bunu tekrar tekrar kullanacaksanız, sıralanmış işlevi çağırarak genel masraf oluşacaktır, böylece seti değiştirmeyi tamamladığınız sürece sonuç listesini kaydetmek isteyebilirsiniz. Benzersiz öğeleri korumanız ve sıralamanız gerekiyorsa, Yok gibi keyfi bir değere sahip koleksiyonlardan OrderedDict kullanma önerisini kabul ediyorum.


43
OrderedSet'in amacı, öğeleri sete eklendikleri sırayla alabilmektir. Örneğin, SortedSet ... olarak adlandırılabilir
Periyodik Bakım

-4

Bu yüzden ben açıkça açıkça benzersiz olmayan değerleri tanıtmak imkanı vardı küçük bir liste vardı.

Bir tür eşsiz bir listenin varlığını araştırdım, ancak daha sonra öğenin varlığını eklemeden önce test etmenin iyi çalıştığını fark ettim.

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

Bu basit yaklaşımda uyarılar olup olmadığını bilmiyorum, ama sorunumu çözdü.


Bu yaklaşımla ilgili asıl mesele, O (n) 'de eklemenin çalışmasıdır. Yani büyük listelerle yavaşlar. Python'un yerleşik setleri, elemanları daha hızlı ekleme konusunda çok iyidir. Ancak basit kullanım durumları için kesinlikle işe yarıyor!
Draconis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.