【问题标题】:update defaultdict count according to the occurrence of tuples in two lists根据两个列表中元组的出现更新 defaultdict 计数
【发布时间】:2018-11-16 21:49:44
【问题描述】:

我有两个列表,想创建一个字典来记录元组的出现。

我当前的代码:

tup_to_find_test = [('good', 'pea'), ('leaf', 'sweet')] 
self_per_list_test = [('leaf', 'liquid'), ('leaf', 'sweet'), ('leaf', 'sweet'),('good', 'pea'),('good', 'pea'),('good', 'pea')]
from collections import defaultdict
tup_dict_test = defaultdict(int)
for tup_to_find_test in self_per_list_test:
   tup_dict_test[tup_to_find_test]+=1

我的结果是:

defaultdict(int, {('leaf', 'liquid'): 1, ('leaf', 'sweet'): 1, ('good', 'pea'): 3})

我想要的结果是:

('leaf', 'liquid'): 0, ('leaf', 'sweet'): 2, ('good', 'pea'): 3})

不知道为什么('leaf', 'liquid')的计数是1。defaultdict(int)的默认整数不就是零吗?为什么('leaf', 'liquid') tuple 得到 1?

【问题讨论】:

  • 你在self_per_list_test 中有一次('leaf', 'liquid'),所以它的计数是1

标签: python list dictionary tuples counter


【解决方案1】:

这条线并没有像你想象的那样做:

for tup_to_find_test in self_per_list_test:
   # ...

您在此处逐元素迭代列表,在本例中为self_per_list_test 的元素。 没有过滤。当您的for 循环迭代时,tup_to_find_test 依次代表('leaf', 'liquid')、('leaf', 'sweet') 等。名称与您之前定义的变量相同的事实只会造成混淆。

相反,您可以使用三元语句来区分操作:

for item in self_per_list_test:
    tup_dict_test[item] += 1 if item in tup_to_find_test else 0

print(tup_dict_test)

defaultdict(int, {('leaf', 'liquid'): 0, ('leaf', 'sweet'): 2, ('good', 'pea'): 3})

collections.Counter 更符合 Python 的习惯。在字典理解中使用 set 进行 O(1) 查找是一种很好的做法。

from collections import Counter

tup_to_find_set = set(tup_to_find_test)
counts = Counter(self_per_list_test)

tup_dict_test = {k: v if k in tup_to_find_set else 0 for k, v in counts.items()}

print(tup_dict_test)

{('leaf', 'liquid'): 0, ('leaf', 'sweet'): 2, ('good', 'pea'): 3}

【讨论】:

  • 这是@BernardL 解决方案的单线时尚对吧?它非常整洁和聪明!谢谢!!!
  • @Abbey,是的,如果你想坚持使用defaultdict,它确实是单行的。建议通过set 使用散列来提高效率。
【解决方案2】:

defaultdict(int)的默认整数不是零吗?

是的。

为什么我的 ('leaf', 'liquid') 元组得到 1?

你写道:

tup_dict_test[tup_to_find_test]+=1

也就是说,找到当前值(创建一个设置为零的新值),然后将其加一并将结果存储回来。结果值为 1。

【讨论】:

    【解决方案3】:

    无需重新发明轮子。为此,您可以使用美妙的collections 标准模块库中的counter。

    from collections import Counter
    
    tup_to_find_test = [('good', 'pea'), ('leaf', 'sweet')] 
    self_per_list_test = [('leaf', 'liquid'), ('leaf', 'sweet'), ('leaf', 'sweet'),('good', 'pea'),('good', 'pea'),('good', 'pea')]
    
    c = Counter(self_per_list_test)
    
    for key in c:
        if key not in tup_to_find_test:
            c[key] = 0
    
    print(c)
    
    >>Counter({('good', 'pea'): 3, ('leaf', 'sweet'): 2, ('leaf', 'liquid'): 0})
    

    这里我们基于self_per_list_test 创建一个计数器,如果在tup_to_find_test 中找不到它,则将计数更新为零。希望这是解决您问题的更直观的方法。

    【讨论】:

    • 一个简单的问题。与defaultdict相比,Counter是否比使用defaultdict更快?
    • 好吧,您不能将defaultdict 与Counter 进行比较,defaultdict 调用工厂函数来提供缺失值。 Counter 被优化以计算可散列值。在这个用例中,如果您的目的只是计数,我会选择 Counter。
    • 我在我的数据集上尝试了这两种方法。你说的对。由于我的目标是简单地计算元组的频率,我应该选择Counter。感谢您的智能/直接解决方案! (我想我的问题想多了)
    • 是的,希望它有所帮助。如果您发现此处的任何答案有用且唉,请在此处接受帮助您解决问题的最佳答案。
    猜你喜欢
    • 2018-11-20
    • 1970-01-01
    • 2017-11-13
    • 2013-09-01
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 2013-04-07
    相关资源
    最近更新 更多