【问题标题】:Python - List of Tuples, sum of tuples having same first value in this case?Python - 元组列表,在这种情况下具有相同第一个值的元组总和?
【发布时间】:2021-03-14 01:18:55
【问题描述】:
li=[('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]

假设我有这种情况。在第一个位置以相同名称开头的地方,我想将第二个添加到第二个,将第三个添加到第三个。

想要的结果:

[('name1', 11, 13), ('name2', 3, 2)]

有谁知道我如何在 Python 中做到这一点?

【问题讨论】:

  • 哇,这是我在这里提出的第一个问题,让我印象深刻的是,我在这么短的时间内已经有了这么多的解决方案。非常感谢大家,我会研究每个答案以提高我的编程技能。感谢大家,我设法解决了我想要的问题。

标签: python list dictionary tuples


【解决方案1】:

给定:

LoT=[('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]

你可以先用一个dict来积累like标签:

di={}
for t in LoT:
    di.setdefault(t[0], []).append(t[1:])

>>> di
{'name1': [(5, 10), (6, 3)], 'name2': [(3, 2)]}

然后用这些标签的总和创建一个新列表:

>>> [(k,)+tuple(map(sum, zip(*li))) for k,li in di.items()]
[('name1', 11, 13), ('name2', 3, 2)]
# the interesting thing here is the zip(*li) which rotates the list of tuples
# zip(*[(5, 10), (6, 3)]) => [(5, 6), (10, 3)]

或者,只保留一个累计:

di={}
for t in LoT:
    try:
        di[t[0]]=tuple(map(sum, zip(di[t[0]], t[1:])))
    except KeyError:
        di[t[0]]=t[1:]

然后将运行的总dict转换为列表:

[(k,)+t for k,t in di.items()]
# same result

无论元组的长度如何,这些解决方案都有效。

【讨论】:

  • 如果 OP 的数据集合每个元素有两个以上的值会怎样?他们每次都必须更新和调整算法吗?
  • 编辑处理长于 2 的元组,但这真的不是问题...
【解决方案2】:
names = [('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]

### Iterate over all members of the original list to perform the logic
new_names = dict()
for n,first,second in names:
    if n not in new_names:
        new_names[n] = (first, second)
    else:
        new_names[n] = (first+new_names[n][0], second+new_names[n][1])

### Get back list of tuples
new_names2 = [(k, *v) for k,v in new_names.items()]
print(new_names2)

输出:

[('name1', 11, 13), ('name2', 3, 2)]

【讨论】:

    【解决方案3】:

    您应该将元组定义为一个类。但是如果数据是作为一组元组给出的......然后定义一个函数addTuple

    def addTuple(t1, t2):
        (ta,va1,va2) = t1
    
        try: (ta,va1,va2) = t1
        except: 
    
            # FIXME: default to None, value 0
            (ta,va1, va2) = (None, 0, 0)
        try:
            # FIXME: default to None, value 0
            (tb,vb1,vb2) = t2
        except: 
            # FIXME: default to None, value 0
            (tb,vb1, vb2) = (None, 0, 0)
    
        return (ta, va1+vb1, va2+vb2)
    
    print([addTuple(arr[0],arr[2]), addTuple(arr[1],0)])
    [('name1', 1
    

    【讨论】:

      【解决方案4】:

      最初元组的值不能改变,但如果你想按照你想要的方式做,那么你可以做这样的事情。

      li = [['name1', 5, 10], ['name2', 3, 2], ['name1', 6, 3]]
      new_li = []
      for tup in li:
          names = [tup[0] for tup in new_li]
          if tup[0] in names:
              index = names.index(tup[0])
              new_li[index][1] += tup[1]
              new_li[index][2] += tup[2]
          else:
              new_li.append(tup)
      
      # [['name1', 11, 13], ['name2', 3, 2]]
      # to make it tuple
      
      new_li = [tuple(l) for l in new_li]
      # [('name1', 11, 13), ('name2', 3, 2)]
      

      【讨论】:

        【解决方案5】:

        另一个答案,但具有一些内置的灵活性:

        li=[('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
        
        # Get length of structure
        li_len = len(li)
        
        # Create empty collection
        outdict = {}
        
        # Iterate over all elements
        for i in range(li_len):
            tmpname = li[i][0] # Temp name variable
            tmpvalues = li[i][1:] # Temp values variable
        
            # If not temp name in dictionary keys
            if not tmpname in outdict:
                # Create entry with values as first values
                outdict[tmpname] = list(tmpvalues)
            else:
                # Otherwise, iterate values and update entry by position
                for j in range(len(tmpvalues)):
                    outdict[tmpname][j] += tmpvalues[j]
        
        # Reformat for output
        result = [tuple([k] + v) for k, v in outdict.items()]
        
        # Print result
        print(result)
        

        输出:

        [('name1', 11, 13), ('name2', 3, 2)]
        

        【讨论】:

          【解决方案6】:

          这是一个使用类定义的方法:

          class mytuple(object):
              def __init__(self, tx, val1, val2):
                  self.tx = tx
                  self.val1 = val1
                  self.val2 = val2
          
              def __add__(self, t2):
                  if self.tx != t2.tx : 
                      print("WARNING: BAD TUPLE, ignoring", self.tx, t2.tx)
          
                  return mytuple(self.tx, 
                                 self.val1 + t2.val1,
                                 self.val2 + t2.val2)
          
              def __str__(self):
                  self.__repr()
          
              def __repr__(self):
                  tstr = ', '.join([self.tx, 
                                  '%d'%self.val1,
                                  '%d'%self.val2])
                  return('(%s)'%tstr)
          
          arr = [ mytuple('name1', 5, 10),
                  mytuple('name2', 3, 2), 
                  mytuple('name1', 6, 3)]
          
          print([arr[0] + arr[2], arr[1]])
          [(name1, 11, 13), (name2, 3, 2)]
          

          【讨论】:

            【解决方案7】:

            更简单的解决方案:

            i = [('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
            d = {}
            for name, fv, sv in i:
                if name not in d:
                    d[name] = [name, fv, sv]
                else:
                    d[name][1] += fv
                    d[name][2] += sv
                    
            [tuple(v) for v in d.values()]
            

            【讨论】:

              猜你喜欢
              • 2018-12-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-03-21
              • 2015-12-22
              • 1970-01-01
              • 2022-10-21
              相关资源
              最近更新 更多