2012-04-16 136 views
31

是否有标准方式来表示可以包含重复元素的“集合”?带有重复/重复元素的Python“集合”

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

我目前使用的元素作为键和数量作为值的字典,但这似乎是错误的原因很多。

动机: 我相信有这样一个集合的许多应用程序。例如,对喜欢的颜色的调查可以表示为: 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'] 

注: 是,设置是不是这个类型的集合正确的称呼。有更正确的吗?

列表当然可以工作,但所需的集合是无序的。更不用说为集合命名的方法在我看来更合适。

+0

这可能有助于解释你为什么要这样做。 – jamylak 2012-04-16 14:29:23

+2

如果你需要重复,它不是定义的“集合”。你能证明你的想法吗?也许我们可以建议一个合适的容器或数据类型? – 2012-04-16 14:29:47

+2

是的,这被称为“列表” – georg 2012-04-16 14:32:43

回答

30

您正在查找multiset

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

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

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

+3

collections.Counter和pypi包之间有什么区别? – max 2012-04-20 08:35:57

+0

关于python 2.7.6我可以运行包,为什么? – Zen 2014-07-01 03:32:40

+5

这里有一个大问题:'len(counter_obj)'给你独特元素的数量,但不是你想要从多重集合中得到的元素总数。但是,您可以像组合和交集一样执行所有其他操作,就像使用集合一样。 – Phani 2015-02-20 13:52:09

11

你的方法与元素/计数字典似乎对我来说还可以。您可能需要更多功能。看看collections.Counter

  • O(1)试验的元素是否存在和当前计数的检索
  • counter.elements()看起来像所有的列表(比element in listlist.count(element)更快)复制
  • 容易操作工会/与其它计数器差
-2

如果您需要重复项,请使用列表,并在您需要以集合形式操作时将其转换为集。

+1

OP最有可能寻找多重集,并将列表转换为集合重复。 – ComputerFellow 2017-02-07 09:29:50

+0

我在编辑之前发布了这个答案。我的方法是只使用该集作为原始列表的视图。 – 2017-02-07 12:33:02

0

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

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

my_list.count(1) # will return 2 
0

另一种Python multiset实现使用排序列表数据结构。 PyPI上有几个实现。一种选择是实现SortedList数据类型的sortedcontainers模块,该数据类型有效地实现类似集合的方法,如add,removecontains。 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模块还维护performance comparison与其他流行的实现。

0

什么你要找的的确是一个multiset(或),不一定是不同元素的集合(而设置不包含重复)。

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

多重数据结构称为bag。 A bag是来自collections模块的Set类的一个子类,带有一个额外字典以跟踪元素的多重性。

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