web-dev-qa-db-ja.com

Pythonには順序集合がありますか?

Pythonには 順序付き辞書 があります。オーダードセットはどうですか?

395
Casebash

これには 順序付きセット (可能な 新しいリンク )レシピがありますは Python 2 Documentation から参照されています。これはPy2.6以降と3.0以降で動作します。初期化はリストを使って行うべきであることを除けば、インタフェースは通常の集合とほとんど同じです。

OrderedSet([1, 2, 3])

これはMutableSetなので、.unionのシグネチャはsetのシグネチャと一致しませんが、__or__が含まれているため、同様のものを簡単に追加できます。

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

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

順序付き集合は、機能的には順序付き辞書の特別な場合です。

辞書のキーはユニークです。したがって、(例えばそれらにNoneを割り当てることによって)順序付けられた辞書内の値を無視するならば、人は本質的に順序付けされたセットを持つ。

Python 3.1 では collections.OrderedDict があります。以下は、OrderedSetの実装例です。 (collections.OrderedDictcollections.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 = property(lambda self: self.__sub__)
    difference_update = property(lambda self: self.__isub__)
    intersection = property(lambda self: self.__and__)
    intersection_update = property(lambda self: self.__iand__)
    issubset = property(lambda self: self.__le__)
    issuperset = property(lambda self: self.__ge__)
    symmetric_difference = property(lambda self: self.__xor__)
    symmetric_difference_update = property(lambda self: self.__ixor__)
    union = property(lambda self: self.__or__)
131
Stephan202

私はOrderedSetよりも優れた方法があります。boltonsは 純粋なPython、2/3互換のIndexedSet を持っています。 (インデックスと同様に)インデックスもサポートします。

単に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を書きましたが、それはまた あなたが何か問題があれば私をバグにすることができることを意味します 。 :)

36
Mahmoud Hashemi

PyPIの実装

Pythonには挿入順保存セットの組み込み実装はまだないことを他の人が指摘していますが、この質問には PyPI に何が見つかるかを示す答えが欠けていると思います) 。

私の知る限りでは、現在のところ、

どちらの実装も Raymond HettingerによってActiveState に投稿されたレシピに基づいています。これは他の回答でも説明されています。両方をチェックアウトし、次のことを確認しました。

重要な違い:

  • ordered-set(version 1.1)
    • 利点:インデックスによる検索のためのO(1)(例:my_set[5]
    • デメリット:remove(item)は実装されていません
  • オフセット(バージョン0.1.3)
    • 利点:remove(item)の場合はO(1)
    • デメリット:インデックスによる検索では明らかにO(n)

両方の実装とも、add(item)__contains__(item)item in my_set)に対してO(1)を持ちます。

残念ながら、どちらの実装にもset1.union(set2) - >のようなメソッドベースの集合演算はありません。代わりにset1 | set2のような演算子ベースの形式を使用する必要があります。集合演算メソッドの完全なリストとそれに対応する演算子ベースの等価物については、_(PythonのSet Objects に関するドキュメント)を参照してください。

私が最初にremove(item)を使ってスクリプトをNotImplementedErrorでクラッシュさせるまで、私はordered-setを最初に使いました。これまでインデックスによるルックアップを使ったことがないので、その間はosetに切り替えました。

あなたがPyPIの他の実装について知っているなら、コメントで教えてください。

33
Daniel K

答えはいいえですが、Python標準ライブラリの collections.OrderedDict をキー(およびNoneとしての値)だけで使用することもできます。

更新:Python 3.7(およびCPython 3.6)以降、標準のdictで、順序を維持することが保証されていますOrderedDict。 (移植性と読みやすさのために、OrderedDictを使い続けたいと思うかもしれません。)

これは、dictを順序付きセットとして使用して、順序を維持しながら重複項目を除外し、それによって順序付きセットをエミュレートする方法の例です。 dictクラスのメソッドfromkeys()を使って辞書を作成してから、keys()を返してください。

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

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

ソート順を維持するためにオーダードセットを使用している場合は、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 データ型があり、これを使ってbagを効率的に実装できます。

16
GrantJ

コードですでにパンダを使用している場合、そのIndexオブジェクトは、この記事の に示すように、順序付きセットのように動作します

7
Berislav Lopac

公式図書館には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']
}
6
DummyHead

ゲームには少し遅れましたが、私はsetlistSequenceの両方を完全に実装するcollections-extendedの一部としてクラス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

6
Michael Lenzen

多くの目的のためには、単に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]

これを繰り返し使用する場合は、ソートされた関数を呼び出すことによってオーバーヘッドが発生するため、セットの変更が完了している限り、結果のリストを保存することをお勧めします。あなたがユニークな要素を維持してソートする必要があるならば、私はNoneのような任意の値でコレクションからOrderedDictを使うことの提案に同意します。

5
hwrd

ParallelRegression パッケージは、より詳細な setList() 順序集合クラスを提供します。 ActiveStateレシピに基づくオプションよりもmethod-complete。リストで利用可能なすべてのメソッドと、セットで利用可能なすべてのメソッドではないにしても大部分をサポートします。

3
RichardB