【问题标题】:Sum numbers by letter in list of tuples在元组列表中按字母对数字求和
【发布时间】:2017-02-05 16:03:28
【问题描述】:

我有一个元组列表:

[ ('A',100), ('B',50), ('A',50), ('B',20), ('C',10) ]

我试图总结所有具有相同字母的数字。 IE。我要输出

[('A', 150), ('B', 70), ('C',10)] 

我尝试使用 set 来获取唯一值,但是当我尝试将第一个元素与 set 进行比较时,我得到了

TypeError: unsupported operand type(s) for +: 'int' and 'str'

有什么快速的方法可以按字母匹配数字吗?

【问题讨论】:

  • 根据您的错误消息,您正在尝试将一个字符串和一个整数相加,如果不进行类型转换,这是非法的。
  • 使用集合来提取唯一值。然后使用嵌套循环查找与集合匹配的数字的值,然后将它们相加。我知道如何以巨大的计算成本来做到这一点,但如果我有几百万个条目,那将需要很长时间
  • 不是我有一个庞大的数据集需要执行计算,而且我的方法太慢了
  • 人们在直接回答具体问题时经常会迷失方向,而没有解决根本问题。为什么你会得到一个这样的元组列表?在 Python 中处理数据有很多更好的方法(例如 defaultdicts)。

标签: python list tuples


【解决方案1】:

这是一个(半?)-liner:按字母分组(您需要先对其进行排序),然后取元组的第二个条目的总和。

from itertools import groupby
from operator import itemgetter

data = [('A', 100), ('B', 50), ('A', 50), ('B', 20), ('C', 10)]
res = [(k, sum(map(itemgetter(1), g)))
       for k, g in groupby(sorted(data, key=itemgetter(0)), key=itemgetter(0))]
print(res)
// => [('A', 150), ('B', 70), ('C', 10)]

上面是 O(n log n)——排序是最昂贵的操作。如果您的输入列表确实很大,那么以下 O(n) 方法可能会更好地为您服务:

from collections import defaultdict

data = [('A', 100), ('B', 50), ('A', 50), ('B', 20), ('C', 10)]

d = defaultdict(int)
for letter, value in data:
    d[letter] += value
res = list(d.items())
print(res)
// => [('B', 70), ('C', 10), ('A', 150)]

【讨论】:

    【解决方案2】:
    >>> from collections import Counter
    >>> c = Counter()
    >>> for k, num in items:
            c[k] += num
    
    
    >>> c.items()
    [('A', 150), ('C', 10), ('B', 70)]
    

    效率较低(但更好看)的一个班轮版本:

    >>> Counter(k for k, num in items for i in range(num)).items()
    [('A', 150), ('C', 10), ('B', 70)]
    

    【讨论】:

    • downvote 可能是因为看到“计数器”和“总和”而不是阅读你如何解决求和而不是计算它:) 有另一个
    【解决方案3】:

    这个怎么样:(假设a是你提供的元组的名字)

    letters_to_numbers = {}
    for i in a:
        if i[0] in letters_to_numbers:
            letters_to_numbers[i[0]] += i[1]
        else:
            letters_to_numbers[i[0]] = i[1]
    b = letters_to_numbers.items()
    

    结果元组 b 的元素没有特定的顺序。

    【讨论】:

      【解决方案4】:

      为了实现这一点,首先创建一个字典来存储您的值。然后使用.items()dict 对象转换为tuple list 以下是如何实现此目的的示例代码:

      my_list = [ ('A',100), ('B',50), ('A',50), ('B',20), ('C',10) ]
      my_dict = {}
      for key, val in my_list:
          if key in my_dict:
              my_dict[key] += val
          else:
              my_dict[key] = val
      
      my_dict.items()
      # Output: [('A', 150), ('C', 10), ('B', 70)]
      

      【讨论】:

        【解决方案5】:

        什么是生成元组列表的?是你吗?如果是这样,为什么不在创建元组列表时尝试使用 defaultdict(list) 将值附加到正确的字母。然后你可以简单地总结它们。请参见下面的示例。

        >>> from collections import defaultdict
        >>> val_store = defaultdict(list)
        >>> # next lines are me simulating the creation of the tuple
        >>> val_store['A'].append(10)
        >>> val_store['B'].append(20)
        >>> val_store['C'].append(30)
        >>> val_store
        defaultdict(<class 'list'>, {'C': [30], 'A': [10], 'B': [20]})
        >>> val_store['A'].append(10)
        >>> val_store['C'].append(30)
        >>> val_store['B'].append(20)
        >>> val_store
        defaultdict(<class 'list'>, {'C': [30, 30], 'A': [10, 10], 'B': [20, 20]})
        
        >>> for val in val_store:
        ...   print(val, sum(val_store[val]))
        ... 
        C 60
        A 20
        B 40
        

        【讨论】:

          【解决方案6】:

          试试这个:

          a = [('A',100), ('B',50), ('A',50), ('B',20), ('C',10) ]
          
          letters = set([s[0] for s in a])
          
          new_a = []
          for l in letters:
              nums = [s[1] for s in a if s[0] == l]
              new_a.append((l, sum(nums)))
          
          print new_a    
          

          结果:

          [('A', 150), ('C', 10), ('B', 70)]
          

          【讨论】:

            【解决方案7】:

            更简单的方法

            x = [('A',100),('B',50),('A',50),('B',20),('C',10)]
            y = {}
            for _tuple in x:
                if _tuple[0] in y:
                    y[_tuple[0]] += _tuple[1]
                else:
                    y[_tuple[0]] = _tuple[1]
            print [(k,v) for k,v in y.iteritems()]
            

            【讨论】:

              【解决方案8】:

              一个班轮:

              >>> x = [ ('A',100), ('B',50), ('A',50), ('B',20), ('C',10) ]
              >>> {
              ...     k: reduce(lambda u, v: u + v, [y[1] for y in x if y[0] == k])
              ...     for k in [y[0] for y in x]
              ...     }.items()
              [('A', 150), ('C', 10), ('B', 70)]
              

              【讨论】:

                猜你喜欢
                • 2016-03-04
                • 2021-08-14
                • 2014-10-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-10-14
                • 1970-01-01
                • 2020-09-16
                相关资源
                最近更新 更多