web-dev-qa-db-ja.com

Python "set" with duplicate / repeated elements

重複する要素を含めることができる「セット」を表す標準的な方法はありますか?.

私が理解しているように、セットには要素が1つまたは0つあります。機能に任意の数を持たせたい。

現在、要素をキー、数量を値として持つ辞書を使用していますが、これは多くの理由で間違っているようです。

動機:このようなコレクションには多くの用途があると思います。たとえば、お気に入りの色の調査は次のように表すことができます。survey= ['blue'、 'red'、 'blue'、 'green']

ここでは、注文は関係ありませんが、数量は関係あります。私は次のようなことをしたいです:

survey.add('blue')
# would give survey == ['blue', 'red', 'blue', 'green', 'blue']

...そして多分

survey.remove('blue')
# would give survey == ['blue', 'red', 'green']

Notes:はい、setはこの種のコレクションの正しい用語ではありません。もっと正しいものはありますか?

もちろんリストは機能しますが、必要なコレクションは順不同です。言うまでもなく、セットのメソッド命名はより適切に思えます。

36
cammil

multiset を探しています。

Pythonに最も近いデータ型は collections.Counter

Counterは、ハッシュ可能なオブジェクトをカウントするためのdictサブクラスです。これは、要素が辞書キーとして格納され、それらの数が辞書値として格納される、順序付けされていないコレクションです。カウントは、ゼロまたは負のカウントを含む任意の整数値にすることができます。 Counterクラスは、他の言語のバッグまたはマルチセットに似ています。

マルチセットの実際の実装では、pypiのデータ構造パッケージの bag クラスを使用します。これはPython 3の場合のみです。Python 2が必要な場合、 ここbag Python 2.4。

34

Element/countを使用したdictでのアプローチは私には問題ないようです。おそらく、さらにいくつかの機能が必要です。 _collections.Counter_ をご覧ください。

  • O(1) test whether an element is present and current count retrieval (faster than with _element in list_ and list.count(element))
  • counter.elements()はすべて重複するリストのように見えます
  • 他のカウンターとの簡単な操作の結合/違い
14
eumiro

あなたが探しているのは確かに multiset (またはbag)、必ずしも別個の要素のコレクションではありません(setは重複を含みません)。

ここにマルチセットの実装があります: https://github.com/mlenzen/collections-extended (Pypyの collections extended モジュール)。

マルチセットのデータ構造はbagと呼ばれます。 bagは、Setモジュールのcollectionsクラスのサブクラスであり、要素の多重度を追跡するための追加の辞書を備えています。

class _basebag(Set):
    """
    Base class for bag and frozenbag.   Is not mutable and not hashable, so there's
    no reason to use this instead of either bag or frozenbag.
    """
    # Basic object methods

    def __init__(self, iterable=None):
        """Create a new basebag.

        If iterable isn't given, is None or is empty then the bag starts empty.
        Otherwise each element from iterable will be added to the bag
        however many times it appears.

        This runs in O(len(iterable))
        """
        self._dict = dict()
        self._size = 0
        if iterable:
            if isinstance(iterable, _basebag):
                for elem, count in iterable._dict.items():
                    self._inc(elem, count)
            else:
                for value in iterable:
                    self._inc(value)

bagのniceメソッドはnlargest(リストのCounterと同様)であり、各要素の出現回数が維持されるため、すべての要素の多重度を非常に高速に返しますバッグの辞書の-to-date:

>>> b=bag(random.choice(string.ascii_letters) for x in xrange(10))
>>> b.nlargest()
[('p', 2), ('A', 1), ('d', 1), ('m', 1), ('J', 1), ('M', 1), ('l', 1), ('n', 1), ('W', 1)]
>>> Counter(b)
Counter({'p': 2, 'A': 1, 'd': 1, 'm': 1, 'J': 1, 'M': 1, 'l': 1, 'n': 1, 'W': 1}) 
0
user2314737

重複/繰り返される要素を持つPythonの「設定」

これは、セットの定義方法によって異なります。 OPにそれを仮定するかもしれません

  1. 順序は関係ありません(順序付けされているかどうかに関係なく)
  2. 複製/繰り返し要素(別名multiplicites)は許可されます

これらの仮定が与えられた場合、オプションは2つの抽象型(a list または multiset )に減少します。 Pythonでは通常、これらの型はそれぞれlistおよびCounterに変換されます。観察するいくつかの機微に関する詳細を参照してください。

与えられた

import random

import collections as ct

random.seed(123)


elems = [random.randint(1, 11) for _ in range(10)]
elems
# [1, 5, 2, 7, 5, 2, 1, 7, 9, 9]

コード

複製要素のリスト:

list(elems)
# [1, 5, 2, 7, 5, 2, 1, 7, 9, 9]

複製要素の「マルチセット」:

ct.Counter(elems)
# Counter({1: 2, 5: 2, 2: 2, 7: 2, 9: 2})

詳細

データ構造について

ここには混乱しやすい用語が混在しています。明確にするために、Pythonのものと比較したいくつかの基本的な数学的データ構造を次に示します。

Type        |Abbr|Order|Replicates|   Math*   |   Python    | Implementation
------------|----|-----|----------|-----------|-------------|----------------
Set         |Set |  n  |     n    | {2  3  1} |  {2, 3, 1}  | set(el)
Ordered Set |Oset|  y  |     n    | {1, 2, 3} |      -      | list(dict.fromkeys(el)
Multiset    |Mset|  n  |     y    | [2  1  2] |      -      | <see `mset` below>
List        |List|  y  |     y    | [1, 2, 2] |  [1, 2, 2]  | list(el)

この表から、各タイプの定義を推測できます。例:setは、順序を無視して複製要素を拒否するコンテナです。対照的に、listは、順序を保持し、要素の複製を許可するコンテナです。

また、表から、次のことがわかります。

  • 順序付きセットとマルチセットの両方がPythonで明示的に実装されていない
  • 「順序」は、要素のランダムな配置に反する用語です。並べ替えまたは挿入順
  • セットとマルチセットは厳密に順序付けられていません。それらは注文できますが、順序は関係ありません。
  • マルチセットはレプリケートを許可するため、厳密なセットではありません(「 set という用語は確かに 混乱 )」。

マルチセットについて

collections.Counterはマルチセットです。多くの場合それをそのように扱うことは安全ですが、Counterは単にkey-multiplicityペアのdict(マッピング)であることに注意してください。多重度の地図です。フラット化されたマルチセットの要素の例を参照してください。

mset = [x for k, v in ct.Counter(elems).items() for x in [k]*v]
mset
# [1, 1, 5, 5, 2, 2, 7, 7, 9, 9]

順序が残っていることに注意してください。無秩序な結果が予想される場合は、驚くかもしれません。しかし、無秩序は秩序を排除するものではありません。したがって、Counterからマルチセットを生成できますが、Pythonでの残差の順序に関する次の条件に注意してください。

  • 複製はマッピングでグループ化され、ある程度の順序が導入されます
  • Python 3.6では、dictは挿入順序を保持します

まとめ

Pythonでは、マルチセットは多重度のマップ、つまりCounterに変換できます。これは、純粋なセットのようにランダムに順序付けされていません。マルチセットでは一般に順序は問題にならないため、ほとんどの場合は問題ありません。

関連項目

  • collections-extended -collectionsの追加データ型のパッケージ
  • N. Wildbergerの 講義 数学的データ構造について

*数学的には、( N。Wildberger に従って、中括弧を表します{}は、セットと括弧を意味します[] Pythonで見られるように、リストを意味します。 Pythonとは異なり、コンマ,は、順序を意味します。

0
pylang

要素の「数」にアクセスしたいときはいつでも、プレーンなlistを使用し、list.count(element)を使用できます。

my_list = [1, 1, 2, 3, 3, 3]

my_list.count(1) # will return 2
0
cfedermann

代替Pythonマルチセット実装は、ソートされたリストのデータ構造を使用します。PyPIにはいくつかの実装があります。1つのオプションは sortedcontainers モジュールで、 SortedListaddremovecontainsなどのセットのようなメソッドを効率的に実装するデータ型。sortedcontainersモジュールは、純粋なPythonで実装され、Cとして高速実装(さらに高速)、100%の単体テストカバレッジ、数時間のストレステスト。

PyPIからのインストールは簡単です。

pip install sortedcontainers

できない場合pip install次に、sortedlist.pyファイルを open-source repository からプルダウンします。

セットと同じように使用します。

from sortedcontainers import SortedList
survey = SortedList(['blue', 'red', 'blue', 'green']]
survey.add('blue')
print survey.count('blue') # "3"
survey.remove('blue')

Sortedcontainersモジュールは、他の一般的な実装と パフォーマンス比較 も維持します。

0
GrantJ