计算(词典列表)列表中最常见的列表

时间:2012-05-03 12:42:46

标签: python collections counter

我有以下数据结构:

data = [[{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}],
        [{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}],
        [{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}],
        [{'Posit': '0', 'R': '255', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '0', 'B': '255', 'G': '0'}],
        [{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}],
        [{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}],
        [{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}],
        [{'Posit': '0', 'R': '0', 'B': '0', 'G': '255'}, {'Posit': '1000', 'R': '255', 'B': '0', 'G': '0'}]]

我想在上面的数据结构中找到最常用的词典列表。

我的第一个想法是使用most_common中的collections.Counter函数,但

from collections import Counter
c = Counter()
for point in data:
    c[point] += 1

TypeError而失败,因为列表不可用。

我的下一个想法是将列表转换为元组,因为元组是不可变的

from collections import Counter
c = Counter()
for point in data:
    c[tuple(point)] += 1

然后我得到一个TypeError说字典也是不可用的。

那么什么是Pythonic的方法来实现我想要的呢?

2 个答案:

答案 0 :(得分:1)

您可以使用Counter,但您必须将列表转换为元组和字典,并将其转换为元组的元组元组(元组键值的元组,以便能够比较两个字典)。

>>> Counter(tuple(tuple(sorted(d.items())) for d in a) for a in data).most_common()

[(((('B', '0'), ('G', '255'), ('Posit', '0'), ('R', '0')),
   (('B', '0'), ('G', '0'), ('Posit', '1000'), ('R', '255'))),
  7),
 (((('B', '0'), ('G', '255'), ('Posit', '0'), ('R', '255')),
   (('B', '255'), ('G', '0'), ('Posit', '1000'), ('R', '0'))),
  1)]

正如@Marcin正确评论tuple(sorted(d.items()))可以替换为更合适的frozenset(d.items())

>>> Counter(tuple(frozenset(d.items()) for d in a) for a in data).most_common()
[((frozenset([('Posit', '0'), ('B', '0'), ('G', '255'), ('R', '0')]),
   frozenset([('R', '255'), ('G', '0'), ('B', '0'), ('Posit', '1000')])),
  7),
 ((frozenset([('Posit', '0'), ('R', '255'), ('B', '0'), ('G', '255')]),
   frozenset([('B', '255'), ('G', '0'), ('R', '0'), ('Posit', '1000')])),
  1)]

答案 1 :(得分:1)

from collections import namedtuple, Counter
# You can probably think of a better name than this
datum = namedtuple('datum', 'Posit R B G')
Counter(tuple(datum(**d) for d in a) for a in data).most_common()
# You might actually want to make the conversion permanent;
# the data is possibly easier to work with that way given the
# fixed key structure, and it should save memory too