【问题标题】:Python - count and group items in list stored in dictionaryPython - 对存储在字典中的列表中的项目进行计数和分组
【发布时间】:2017-05-15 09:57:40
【问题描述】:

我已经看到了有关如何计算字典或列表中的项目的示例。我的字典存储了多个列表。每个列表存储多个项目。

d = dict{}
d  = {'text1': ['A', 'C', 'E', 'F'], 
      'text2': ['A'], 
      'text3': ['C', 'D'], 
      'text4': ['A', 'B'], 
      'text5': ['A']}

1.我想计算每个字母的频率,即结果应该是

A - 4  
B - 1  
C - 2  
D - 1  
E - 1  
F - 1

2. 我想按每个字母进行分组,即结果应该是

A - text1, text2, text4, text5  
B - text4  
C - text1, text3  
D - text3  
E - text1  
F - text1  

如何通过使用一些 Python 现有库而不使用许多 for 循环来实现这两者?

【问题讨论】:

  • 列表会有重复项吗?
  • 那么你在哪里失败了?请发布您迄今为止尝试过的代码。
  • 我还没有其他代码。我可以编写循环来找到答案,但我敢打赌必须有一些库(集合?)才能做到这一点。
  • 列表没有重复项
  • 你认为'许多' for 循环是什么?它们的存在是有原因的,这个用例对它们来说是一个很好的用例。你有想要避开它们的理由吗?

标签: python list dictionary collections grouping


【解决方案1】:

要达到 (2),您必须首先反转字典的键和值,并将它们存储在列表中。到达那里后,使用带有密钥的groupby 进入 (2) 的结构。

from itertools import groupby

arr = [(x,t) for t, a in d.items() for x in a]
# [('A', 'text2'), ('C', 'text3'), ('D', 'text3'), ('A', 'text1'), ('C', 'text1'), ('E', 'text1'), ('F', 'text1'), ('A', 'text4'), ('B', 'text4'), ('A', 'text5')]

res = {g: [x[1] for x in items] for g, items in groupby(sorted(arr), key=lambda x: x[0])}
#{'A': ['text1', 'text2', 'text4', 'text5'], 'C': ['text1', 'text3'], 'B': ['text4'], 'E': ['text1'], 'D': ['text3'], 'F': ['text1']}

res2 = {x: len(y) for x, y in res.items()}
#{'A': 4, 'C': 2, 'B': 1, 'E': 1, 'D': 1, 'F': 1}

PS:我希望您在真实代码中使用有意义的变量名。

【讨论】:

  • 你能解释一下 res 行吗? groupby 和 lambda 是如何一起使用的?
【解决方案2】:

有几种方法可以实现这一点,但如果您想处理事情而不用担心 import 附加模块或安装和导入外部模块,这种方法将“开箱即用”干净利落。

d 作为您的起始字典:

d  = {'text1': ['A', 'C', 'E', 'F'], 
      'text2': ['A'], 
      'text3': ['C', 'D'], 
      'text4': ['A', 'B'], 
      'text5': ['A']}

创建一个新的dict,称为letters,用于存放您的结果,并用取自d.keys() 的字母填充它,方法是创建不存在的字母键,并创建一个列出来自d的计数和键,因为它的值。如果它已经存在,则增加计数,并将当前键从 d 添加到值中的 d 键列表中。

letters = {}
for item in d.keys():
    for letter in d[item]:
        if letter not in letters.keys():
            letters[letter] = [1,[item]]            
        else:
            letters[letter][0] += 1
            letters[letter][1] += [item]

这会给您留下一个名为lettersdict,其中包含计数值和来自d 的包含字母的键,如下所示:

{'E': [1, ['text1']], 'C': [2, ['text3', 'text1']], 'F': [1, ['text1']], 'A': [4, ['text2', 'text4', 'text1', 'text5']], 'B': [1, ['text4']], 'D': [1, ['text3']]}`

现在,要打印您的第一个列表,请执行以下操作:

for letter in sorted(letters):
    print(letter, letters[letter][0])

打印每个字母和列表的第一个或“计数”索引的内容作为其值,并使用内置的sorted() 函数来整理。

要打印第二个,同样是sorted(),执行相同操作,但在其值中使用列表的第二个或“键”索引,.joined 使用, 到字符串中:

for letter in sorted(letters):
    print(letter, ', '.join(letters[letter][1]))

为了方便复制/粘贴,以下是我漫无目的的代码:

d  = {'text1': ['A', 'C', 'E', 'F'], 
      'text2': ['A'], 
      'text3': ['C', 'D'], 
      'text4': ['A', 'B'], 
      'text5': ['A']}

letters = {}
for item in d.keys():
    for letter in d[item]:
        if letter not in letters.keys():
            letters[letter] = [1,[item]]            
        else:
            letters[letter][0] += 1
            letters[letter][1] += [item]

print(letters)

for letter in letters:
    print(letter, letters[letter][0])
print()
for letter in letters:
    print(letter, ', '.join(letters[letter][1]))

希望这会有所帮助!

【讨论】:

    【解决方案3】:
    from collections import Counter, defaultdict
    from itertools import chain
    d  = {'text1': ['A', 'C', 'E', 'F'], 
          'text2': ['A'], 
          'text3': ['C', 'D'], 
          'text4': ['A', 'B'], 
          'text5': ['A']}
    counter = Counter(chain.from_iterable(d.values()))
    group = defaultdict(list)
    for k, v in d.items():
        for i in v:
            group[i].append(k)
    

    出来:

    Counter({'A': 4, 'B': 1, 'C': 2, 'D': 1, 'E': 1, 'F': 1})
    defaultdict(list,
                {'A': ['text2', 'text4', 'text1', 'text5'],
                 'B': ['text4'],
                 'C': ['text1', 'text3'],
                 'D': ['text3'],
                 'E': ['text1'],
                 'F': ['text1']})
    

    【讨论】:

      【解决方案4】:

      第一个任务:

      from collections import Counter
      
      
      d = {
        'text1': ['A', 'C', 'E', 'F'],
        'text2': ['A'],
        'text3': ['C', 'D'],
        'text4': ['A', 'B'],
        'text5': ['A']
      }
      
      occurrences = Counter(''.join(''.join(values) for values in d.values()))
      print(sorted(occurrences.items(), key=lambda l: l[0]))
      

      现在让我解释一下:

      • ''.join(values) 将列表(例如 ['A', 'B', 'C', 'D'] 转换为 'ABCD' )
      • 然后您将字典中的每个列表加入成一个字符串(外部 ''.join()
      • Counter 是内置包 collections 中的一个类,它简单地计算可迭代对象(在本例中为 string)中的元素并将它们复制为元组(key, value) 对(例如 ('A', 4)
      • 最后,我按字母顺序对 Counter 项(就像字典一样)进行排序(key=lambda l: l[0] where l[0] (key, value) 对中的字母。

      正如我所见,您已经有了第二个问题的解决方案。

      【讨论】:

        【解决方案5】:
        from collections import defaultdict
        
        alphabets = defaultdict(list)
        his is a way to acheive this:
        
            for text, letters in d.items():
                for letter in letters:
                    alphabets[letter].append(text)
        
            for letter, texts in sorted(alphabets.items()):
                print(letter, texts)
        
            for letter, texts in sorted(alphabets.items()):
                print(letter, len(texts))
        

        请注意,如果您有 A - text1, text2, text4, text5A - 4 只是计算文本的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-06
          • 1970-01-01
          • 1970-01-01
          • 2022-12-16
          • 2017-05-24
          • 2019-11-16
          • 1970-01-01
          相关资源
          最近更新 更多