回答:
これには順序付けられたセット(新しいリンクの可能性があります)のレシピがあり、これはPython 2ドキュメントから参照されます。これは、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
update
、union
、intersection
。
union
同じクラスで2つのメソッドを呼び出すことは許可されていません。最後のものは「勝ち」、最初のものは実行時に存在しなくなります。これは、OrderedSet.union
(括弧なし)が単一のオブジェクトを参照する必要があるためです。
辞書のキーは一意です。したがって、順序付けされたディクショナリの値を無視すると(たとえば、値を割り当てることによりNone
)、基本的に順序付けされたセットになります。
Python 3.1にはがありcollections.OrderedDict
ます。以下はOrderedSetの実装例です。(いくつかのメソッドを定義またはオーバーライドする必要があるだけであることに注意してください。collections.OrderedDict
そしてcollections.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__
OrderedSet
どのサブクラスをOrderedDict
してabc.Set
、その後、定義__len__
、__iter__
および__contains__
。
collections
にありますが、それ以外は良い提案です
OrderedSet([1,2,3])
するとTypeErrorが発生します。コンストラクタはどのように機能しますか?使用例がありません。
答えは「いいえ」ですが、同じ目的で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']
dict.fromkeys()
。ただし、その場合、キーの順序はCPython 3.6以降の実装でのみ保持されるため、順序が重要な場合OrderedDict
はよりポータブルなソリューションになります。
keys = (1,2,3,1,2,1)
list(OrderedDict.fromkeys(keys).keys())
-> [1, 2, 3]
、python-3.7。できます。
dict
、set
Python 3.7以降では残念ながら順序が保持されません。
OrderedSetよりも1つ上手くできます。boltonsは、順序付けされたセットであるだけでなく、(リストと同様に)インデックス作成もサポートする、純粋なPythonのIndexedSet
2/3 互換タイプを持っています。
単純に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
することもできます。:)
他の人は、Pythonには(まだ)挿入順序保持セットの組み込み実装がないと指摘しましたが、この質問にはPyPIで何が検出されるかを示す答えが欠けていると感じています。
パッケージがあります:
これらの実装の一部は、レイモンドヘッティンガーがActiveStateに投稿したレシピに基づいています。
my_set[5]
)remove(item)
どちらの実装にも、O(1)add(item)
および__contains__(item)
(item in my_set
)があります。
OrderedSet
現在サポートしていますremove
並べ替え順序を維持するために順序付きセットを使用している場合は、PyPIからの並べ替えセットの実装の使用を検討してください。sortedcontainersのモジュールが提供したSortedSetをこの目的のためだけに。いくつかの利点:純粋なPython、Cとしての高速実装、100%の単体テストカバレッジ、何時間ものストレステスト。
PyPIからのインストールは、pipを使用すると簡単です。
pip install sortedcontainers
できない場合はpip install
、単に、オープンソースリポジトリからsortedlist.pyファイルとsortedset.pyファイルをプルダウンしてください。
インストールしたら、簡単に次のことができます。
from sortedcontainers import SortedSet
help(SortedSet)
sortedcontainersモジュールは、いくつかの代替実装とのパフォーマンス比較も維持します。
Pythonのbagデータ型について尋ねたコメントの代わりに、効率的にバッグを実装するために使用できるSortedListデータ型があります。
SortedSet
そこのクラスでは、メンバーが比較可能でハッシュ可能である必要があることに注意してください。
set
でfrozenset
あり、要素がハッシュ可能であることも必要です。同等の制約はの追加ですSortedSet
が、明らかな制約でもあります。
コードですでにパンダを使用している場合、その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
indA.difference(indB)
。マイナス記号は標準の減算を実行します
少し遅れてゲームに、私はクラスを書いているsetlist
の一環として、collections-extended
その完全実装の両方Sequence
と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-extended
ドキュメント:http : //collections-extended.lenzm.net/en/latest/
PyPI:https ://pypi.python.org/pypi/collections-extended
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']
}
ParallelRegressionのパッケージが提供してセットリストを()よりメソッド完全ActiveStateのレシピに基づいたオプションよりもセットクラスを命じました。リストで使用できるすべてのメソッド、およびセットで使用できるすべてではないにしてもほとんどのメソッドをサポートします。
他の回答が述べているように、Python 3.7+に関しては、dictは定義により順序付けられています。サブクラス化OrderedDict
する代わりに、サブクラス化しabc.collections.MutableSet
たりtyping.MutableSet
、dictのキーを使用して値を保存したりできます。
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
それを実行できます。
多くの目的で、単にsortedを呼び出すだけで十分です。例えば
>>> 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]
これを繰り返し使用する場合は、sorted関数を呼び出すことによってオーバーヘッドが発生するため、セットの変更が完了している限り、結果のリストを保存する必要があります。一意の要素を維持して並べ替える必要がある場合は、Noneなどの任意の値を持つコレクションからOrderedDictを使用するという提案に同意します。
だから私はまた、一意でない値を導入する可能性があることを明らかにした小さなリストも持っていました。
私はある種のユニークなリストの存在を検索しましたが、追加する前に要素の存在をテストしても問題なく機能することに気付きました。
if(not new_element in my_list):
my_list.append(new_element)
この単純なアプローチに警告があるかどうかはわかりませんが、それで問題が解決します。