【问题标题】:summing tuples in list对列表中的元组求和
【发布时间】:2018-09-09 23:01:30
【问题描述】:

我有一个元组列表:

[(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]

我想对左侧相等的元组的右侧求和,并将其放入另一个元组列表中,所以对于上面的列表,我会得到:

[(0,2),(1,1),(2,1),(3,2),(4,3),(5,2)]

我试过了:

k=0
for i,TCtup in enumerate(wordsMatchingList):
    if wordsMatchingList[i][0]==k:
        TC_matches+=wordsMatchingList[i][1]
        print("k: {} /// TC_matches: {}".format(k,TC_matches)) #for checking
    else:
        groupedWordsMatchingList.append(tuple((k,TC_matches)))
        TC_matches=0
        k+=1

但从 k=1 开始,由于 else 条件,它只为每 k 少循环一次。

谢谢

【问题讨论】:

  • 你看过 itertools.groupby 了吗?
  • 你的元组是否保证是这样排序的?
  • 保罗鲁尼-我现在就去找。
  • abarnert- 是的,它保证是有序的

标签: python python-3.x tuples


【解决方案1】:

如果保证你的元组按这样的顺序排列——所有的(0, x),然后是所有的(1, x),等等——你可以使用groupby

>>> xs = [(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
>>> from itertools import groupby
>>> from operator import itemgetter
>>> groups = groupby(xs, key=itemgetter(0))
>>> ys = [(key, sum(map(itemgetter(1), group))) for key, group in groups]

如果它们不是,但你可以对它们进行排序(你有一个列表,而不仅仅是一个任意可迭代的,而且它不会太大以至于对数线性时间太昂贵) :

>>> groups = groupby(sorted(xs, key=itemgetter(0)), key=itemgetter(0))

如果您无法对它们进行排序,您可以随时手动建立总计:

>>> from collections import Counter
>>> totals = Counter()
>>> for k, v in xs:
...     totals[k] += v
>>> ys = list(totals.items())

【讨论】:

  • e = {}; for k, v in xs: e[k] = e.get(k,0)+v 应该可以工作。我也倾向于认为,与同时使用 groupby、map、sum 和 for 循环的复杂性相比,这将具有最低的复杂性
  • @Onyambu 这与我的上一个版本相同,但为totals 使用一个字母的变量名称,并重复自己以避免使用Counter,并错过了最后一步。另外,如果“最小复杂度”是指计算复杂度,那么是的,正如我所解释的,排序需要对数线性时间;如果你已经完成了,那么剩下的工作就是线性的,否则显然不是。
  • 我不是在说我的。我是说你的第二个答案比你的第一个答案好。别管我写的代码
【解决方案2】:

另一种方式,

t.sort(key=lambda x: x[0]) #sort before groupby (required)
g=itertools.groupby(t, lambda x: x[0])
new_l = []
for k,v in g:
    new_l.append((k, sum([x[1] for x in v])))

【讨论】:

    【解决方案3】:

    另一种方法是使用defaultdict(来自collections)并迭代元组列表。

    from collections import defaultdict
    
    lst = [(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
    
    d = defaultdict(int)
    
    for (u,v) in lst:
        d[u]+=v
    
    # list(d.items()) [(0, 2), (1, 1), (2, 1), (3, 2), (4, 3), (5, 2)]
    

    【讨论】:

      【解决方案4】:

      我建议使用带有groupby 函数的库。例如,pandas 可能很有用

      >>> s = pd.DataFrame(list_)
      >>> s.groupby(0, as_index=False).sum().agg(tuple,1).tolist()
      
      [(0, 2), (1, 1), (2, 1), (3, 2), (4, 3), (5, 2)]
      

      【讨论】:

        【解决方案5】:
        In [5]: [(j, sum([i[1] for i in a if i[0] == j])) for j in set([i[0] for i in a])]
        Out[5]: [(0, 2), (1, 1), (2, 1), (3, 2), (4, 3), (5, 2)]
        

        【讨论】:

        • 您正在为元组的每个不同的左元素迭代整个列表。
        • 是的,我同意,时间复杂度是 O(m*n),但它更容易阅读,并且会像 op 发布的那样为一个小型列表完成工作。
        【解决方案6】:
        lst = [(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
        [(i,sum([q[1] for q in lst if q[0] == i])) for i in range(lst[-1][0]+1)]
        

        给予:

        [(0,2),(1,1),(2,1),(3,2),(4,3),(5,2)]
        

        【讨论】:

          猜你喜欢
          • 2021-06-16
          • 2017-01-04
          • 1970-01-01
          • 1970-01-01
          • 2012-07-05
          • 2021-09-01
          • 2016-03-15
          • 2021-11-23
          • 1970-01-01
          相关资源
          最近更新 更多