Python“设置”具有重复/重复元素

时间:2012-04-16 14:28:01

标签: python collections dictionary set

是否有标准方法来表示可能包含重复元素的“集合”。

据我所知,一个集合只有一个或零个元素。我希望功能有任何数字。

我目前正在使用一个字典,其中元素为键,数量为值,但出于多种原因,这似乎是错误的。

动机: 我相信这样的收藏有很多应用。例如,对喜欢的颜色的调查可以表示为:     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']

备注: 是的,set不是这种集合的正确术语。有更正确的吗?

课程列表可行,但所需的集合是无序的。更不用说用于命名集合的方法在我看来更合适。

9 个答案:

答案 0 :(得分:32)

您正在寻找multiset

Python最接近的数据类型为collections.Counter

  

Counter是用于计算可哈希对象的dict子类。它是一个   无序集合,其中元素存储为字典键和   他们的计数存储为字典值。计数是允许的   任何整数值,包括零或负数。 Counter课程   类似于其他语言的包或多重集。

对于多集的实际实现,请使用pypi上数据结构包中的bag类。请注意,这仅适用于Python 3。如果你需要Python 2,here是为Python 2.4编写的bag的配方。

答案 1 :(得分:13)

你使用带有元素/计数的dict的方法对我来说似乎没问题。您可能需要更多功能。看看collections.Counter

  • O(1)测试元素是否存在和当前计数检索(快于element in listlist.count(element)
  • counter.elements()看起来像一个包含所有重复项的列表
  • 轻松操纵联盟/与其他计数器的区别

答案 2 :(得分:0)

只要您想访问元素的“数量”,就可以使用普通list并使用list.count(element)

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

my_list.count(1) # will return 2

答案 3 :(得分:0)

另一种Python多集实现使用排序列表数据结构。 PyPI上有几个实现。一个选项是sortedcontainers模块,它实现SortedList数据类型,可以有效地实现类似addremovecontains的类似集合的方法。 sortedcontainers模块以纯Python,快速实现(甚至更快)实现,具有100%的单元测试覆盖率和数小时的压力测试。

从PyPI轻松安装:

pip install sortedcontainers

如果你不能pip install,那么只需从open-source repository下拉sortedlist.py文件。

像使用它一样使用它:

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

sortedcontainers模块还维护performance comparison与其他流行的实现。

答案 4 :(得分:0)

你正在寻找的确是multiset(或 bag ),不一定是不同元素的集合(而不包含一式两份)。

这里有一个多集的实现:https://github.com/mlenzen/collections-extended(Pypy的collections extended模块)。

多集的数据结构称为bagbag是来自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的一个很好的方法是nlargest(类似于列表的Counter),它可以快速返回所有元素的多重性,因为每个元素的出现次数都保持不变在袋子词典中的最新日期:

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

答案 5 :(得分:0)

  

带有重复/重复元素的Python“设置”

这取决于您如何定义集合。人们可能会以为

  1. 顺序无关紧要(无论是有序的还是无序的)
  2. 允许复制/重复元素(也称为 multiplicites

基于这些假设,选项减少为两种抽象类型:listmultiset。在Python中,这些类型通常分别转换为listCounter。请参阅“细节”以了解一些细微之处。

给出

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 是一个忽略顺序并拒绝重复元素的容器。相反,列表是一个保留顺序并允许重复元素的容器。

也可以从表中看到:

  • 有序集和多集都没有在Python中明确实现
  • “顺序”是与元素的随机排列相反的术语,例如元素。排序或插入顺序
  • 集和多集不是严格排序的。它们可以 进行排序,但是顺序无关紧要。
  • 多集允许重复,因此它们不是严格的集(术语“ set”的确是confusing)。

关于多重集

有人可能会说collections.Counter是一个多集。在很多情况下,您都可以安全地对待它,但是请注意,Counter仅仅是key- multiplicity 对的字典(映射)。这是一幅多重图。查看展平的多集中元素的示例:

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中,字典的保留插入顺序

摘要

在Python中,可以将多重集转换为多重映射,即Counter,它不会像纯集合那样随机无序。可能会有一些剩余排序,在大多数情况下都可以,因为在多集中排序通常并不重要。

另请参见

*在数学上,(根据N. Wildberger,我们用花括号{}表示一个集合,用括号[]表示一个列表,如Python所示。与Python不同,逗号,表示顺序。

答案 6 :(得分:0)

您已经可以使用collections.Counter来实现多集。

实现多集的另一种方法是使用defaultdict,它可以通过计算出现次数来工作,例如collections.Counter

这是python docs的摘录:

default_factory设置为int使得defaultdict对计数非常有用(例如袋子或其他语言的多件套商品):

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

答案 7 :(得分:0)

访问https://stackabuse.com/sets-in-python

简介

在 Python 中,集合是一种存储无序项的数据结构。设置项也未编入索引。与列表一样,集合允许添加和删除元素。但是,有一些独特的特性定义了一个集合并将其与其他数据结构分开:

集合不包含重复项。

集合的元素是不可变的,即不能改变,但集合本身是可变的,即可以改变。

由于集合项未编入索引,因此集合不支持任何切片或索引操作。

答案 8 :(得分:-2)

如果您需要重复项,请使用列表,并在需要作为一组操作时将其转换为一组。