【问题标题】:Sum nested lists based on condition in Python根据Python中的条件对嵌套列表求和
【发布时间】:2017-04-25 18:05:21
【问题描述】:

我有一个如下所示的嵌套列表:

[['Vienna','2012', 890,503,70],['London','2014', 5400, 879,78],
 ['London','2014',4800,70,90],['Bern','2013',300,450,678], 
 ['Vienna','2013', 700,850,90], ['Bern','2013',500,700,90]]

如果城市和年份相等,我想要做的是将子列表中的每个整数值与另一个子列表相加。我最初想到了一个以城市和年份为键的字典,但它导致了排序问题。

然后我有:{('Vienna','2012'):[890,503,70],('Bern','2013'):[800,1150,768],...}

我也试过这样的:

[sum(x) for x in zip(*list) if x[0] == x[0]] 但当然没用。

我可以用嵌套列表做这样的事情,以便按城市和年份对其进行排序会更容易吗?

【问题讨论】:

    标签: python list nested


    【解决方案1】:

    您可以通过简单地使用字典将所有国家名称和年份存储为一个值来实现您想要的结果。字典中的每个键都是国家名称和对应年份的元组。

    例如:key = (country,year)

    这使我们能够拥有对它们进行分组所需的唯一值。

    L = [
            ['Vienna','2012', 890,503,70],['London','2014', 5400, 879,78],
            ['London','2014',4800,70,90],['Bern','2013',300,450,678],
            ['Vienna','2013', 700,850,90], ['Bern','2013',500,700,90]
        ]
    
        countries = {}
    
        for list in L:
            key = tuple(list[0:2])
            values = list[2:]
            if key in countries:
                countries[key] = [sum(v) for v in zip(countries[key],values)]
            else:
                countries[key] = values
    
        print(countries)
    

    出来:

     {
         ('Vienna', '2012'): [890, 503, 70],
         ('London', '2014'): [10200, 949, 168],
         ('Bern', '2013'): [800, 1150, 768],
         ('Vienna', '2013'): [700, 850, 90]
    }
    

    【讨论】:

      【解决方案2】:

      您可以构造一个结果dict,其中键是原始列表中前两项的元组,值是数字的list。每次向dict 添加值时,您都可以使用get 返回现有元素或给定默认值,在本例中为空列表。

      拥有现有列表和要添加的列表后,您可以使用 zip_longestfillvalue 从两个列表中获取要求和的数字。 zip_longest 返回长度为 2 的元组,每个列表中包含一个数字。如果一个列表比其他列表长,fillvalue 被用作默认值,因此这也适用于列表长度不同的情况。最后,列表推导可以用来对每个项目求和以获得新值:

      from itertools import zip_longest
      
      l = [
          ['Vienna','2012', 890,503,70],['London','2014', 5400, 879,78],
          ['London','2014',4800,70,90],['Bern','2013',300,450,678],
          ['Vienna','2013', 700,850,90], ['Bern','2013',500,700,90]
      ]
      
      res = {}
      for x in l:
          key = tuple(x[:2])
          res[key] = [i + j for i, j in zip_longest(res.get(key, []), x[2:], fillvalue=0)]
      
      print(res)
      

      输出:

      {('Vienna', '2013'): [700, 850, 90], ('London', '2014'): [10200, 949, 168], 
       ('Vienna', '2012'): [890, 503, 70], ('Bern', '2013'): [800, 1150, 768]}  
      

      如果您想首先按字母顺序和年份对城市进行排序,您可以将自定义 key 传递给 sorted

      for item in sorted(res.items(), key=lambda x: (x[0][0], -int(x[0][1]))):
          print(item)
      

      输出:

      (('Bern', '2013'), [800, 1150, 768])
      (('London', '2014'), [10200, 949, 168])
      (('Vienna', '2013'), [700, 850, 90])
      (('Vienna', '2012'), [890, 503, 70])
      

      【讨论】:

      • 这看起来很不错。使用res = collections.OrderedDict() 进行改进。
      • 也可以用defaultdict(list)res[key] 而不是res.get(key, [])
      • @Gribouillis:这完全取决于预期输出的顺序。如果需要的项目与原始列表中的顺序相同,那么它会很有用。
      【解决方案3】:
      nl = [['Vienna','2012', 890,503,70],['London','2014', 5400, 879,78],
            ['London','2014',4800,70,90],['Bern','2013',300,450,678],
            ['Vienna','2013', 700,850,90], ['Bern','2013',500,700,90]]
      d = {}
      for l in nl:
          key = l[0] , l[1]
          value = l[2:]
          if key not in d:
              d[key] = value
          else:
              d[key] = [sum(i)for i in zip(d[key], value)]
      print(d)
      

      出来:

      {('Vienna', '2012'): [890, 503, 70], ('London', '2014'): [10200, 949, 168], ('Bern', '2013'): [800, 1150, 768], ('Vienna', '2013'): [700, 850, 90]}
      

      【讨论】:

        【解决方案4】:

        使用itertools.groupbyoperator.itemgetter函数的解决方案:

        import itertools, operator
        
        l = [['Vienna','2012', 890,503,70],['London','2014', 5400, 879,78],
         ['London','2014',4800,70,90],['Bern','2013',300,450,678],
         ['Vienna','2013', 700,850,90], ['Bern','2013',500,700,90]]
        
        getter = operator.itemgetter(0, 1)  # the sequence to be grouped(first two items)
        summed = [[k[0],k[1],sum(sum(d[2:]) for d in list(group))]
                  for k, group in itertools.groupby(sorted(l, key=getter), getter)]
        
        print(summed)
        

        输出:

        [['Bern', '2013', 2718], ['London', '2014', 11317], ['Vienna', '2012', 1463], ['Vienna', '2013', 1640]]
        

        【讨论】:

          【解决方案5】:

          一种方法是通过您想要的键(城市和年份)将列表列表拆分为一个字典。 defaultdict 还有助于将所有距离压缩到一个平面列表中

          >>> from collections import defaultdict
          >>> dct = defaultdict(list)
          >>> for item in lst:
          ...    dct[(item[0], item[1])].extend(item[2:])
          

          现在dct 具有按城市和年份分组的整数:

          >>> dct
          defaultdict(<type 'list'>, {('Vienna', '2013'): [700, 850, 90], ('London', '2014'): [5400, 879, 78, 4800, 70, 90], ('Vienna', '2012'): [890, 503, 70], ('Bern', '2013'): [300, 450, 678, 500, 700, 90]})
          

          你可以把它们相加:

          >>> for key in dct:
          ...    print(key, sum(dct[key]))
          ... 
          (('Vienna', '2013'), 1640)
          (('London', '2014'), 11317)
          (('Vienna', '2012'), 1463)
          (('Bern', '2013'), 2718)
          

          【讨论】:

            【解决方案6】:

            您应该按照问题中的概述维护一本字典。这样的事情会有所帮助,

            cities = {}
            for a in list:
                city_key = a[:1]
                if city_key in cities:
                    cities[city_key] = [a + b for a, b in zip(a[2:], cities[city_key])]
                else:
                    cities[city_tuple] = a[2:]
            

            【讨论】:

            • 好吧,我已经按照你的方式做了。问题是我需要对输出进行排序。它应该看起来像这样:2014 年维也纳 .... 2013 年 .... 最简单的方法是什么?
            • 您可以轻松地对键进行排序stackoverflow.com/questions/9001509/…
            猜你喜欢
            • 1970-01-01
            • 2021-01-25
            • 2017-06-20
            • 2018-09-15
            • 2021-08-01
            • 2021-10-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多