1

我有一个列表列表。如果存在具有前三个共同元素的子列表,则将它们合并到一个列表中并添加所有第四个元素。

这个问题最好用代码和所需的输出来解释。

a_list = [['apple', 50, 60, 7],
          ['orange', 70, 50, 8],
          ['apple', 50, 60, 12]]

# output:
# [['apple', 50, 60, 19], ['orange', 70, 50, 8]]

我已经有类似问题的代码(前段时间由 Stack Overflow 中的另一个用户给我),但我不完全理解它,所以我无法相应地修改它。这段代码的作用是检查第 0 个和第 2 个元素是否相同,如果相同,则合并子列表,添加第 1 个和第 3 个元素:

import defaultdict
data = [['42x120x1800', 50, '50x90x800', 60],
        ['42x120x1800', 8, '50x90x800', 10],
        ['2x10x800', 5, '5x9x80', 6]]

d = defaultdict(lambda :[0, 0])
for sub_list in data:
    key = (sub_list[0], sub_list[2])
    d[key][0] += sub_list[1]
    d[key][1] += sub_list[3]

new_data = [[key[0], val[0], key[1], val[1]] for key, val in d.iteritems()]
# [['2x10x800', 5, '5x9x80', 6], ['42x120x1800', 58, '50x90x800', 70]]

应该如何修改代码以适应我的新问题?如果您也能花时间彻底解释代码,我将不胜感激。

4

3 回答 3

3

您可以使用相同的原则,通过使用前三个元素作为键,并使用int作为默认值工厂defaultdict(所以你得到0作为初始值):

from collections import defaultdict

a_list = [['apple', 50, 60, 7],
          ['orange', 70, 50, 8],
          ['apple', 50, 60, 12]]

d = defaultdict(int)
for sub_list in a_list:
    key = tuple(sub_list[:3])
    d[key] += sub_list[-1]

new_data = [list(k) + [v] for k, v in d.iteritems()]

如果您使用的是 Python 3,则可以将其简化为:

d = defaultdict(int)
for *key, v in a_list:
    d[tuple(key)] += v

new_data = [list(k) + [v] for k, v in d.items()]

因为您可以使用加星标的目标从列表中获取所有“剩余”值,所以每个子列表主要分配给key,最后一个值分配给,使循环更简单(并且在 dict 中v没有方法.iteritems()Python 3,因为.items()它已经是一个迭代器)。

因此,我们使用 adefaultdict作为0默认值,然后对于从前 3 个值生成的每个键(作为元组,因此您可以将其用作字典键)对最后一个值求和。

  • 因此,对于第一项['apple', 50, 60, 7]我们创建一个 key ('apple', 50, 60),查找它d(它不存在,但defaultdict随后将int()用于创建 的新值0),并7从第一项添加。

  • ('orange', 70, 50)对key 和 value做同样的事情8

  • 对于第三项,我们('apple', 50, 60)再次获得密钥并添加12到预先存在7d[('apple', 50, 60)]. 总共19个。

然后我们将(键,值)对转换回列表,您就完成了。这导致:

>>> new_data
[['apple', 50, 60, 19], ['orange', 70, 50, 8]]

需要对数据进行排序的替代实现使用itertools.groupby

from itertools import groupby
from operator import itemgetter

a_list = [['apple', 50, 60, 7],
          ['orange', 70, 50, 8],
          ['apple', 50, 60, 12]]

newlist = [list(key) + [sum(i[-1] for i in sublists)] 
    for key, sublists in groupby(sorted(a_list), key=itemgetter(0, 1, 2))]

对于相同的输出。如果您的数据未排序,这会变慢,但了解不同的方法是件好事。

于 2013-01-23T21:05:28.223 回答
1

我会做这样的事情:

>>> a_list = [['apple', 50, 60, 7],
...           ['orange', 70, 50, 8],
...           ['apple', 50, 60, 12]]
>>> 
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> from operator import itemgetter
>>> getter = itemgetter(0,1,2)
>>> for lst in a_list:
...     d[getter(lst)].extend(lst[3:])
... 
>>> d
defaultdict(<type 'list'>, {('apple', 50, 60): [7, 12], ('orange', 70, 50): [8]})
>>> print [list(k)+v for k,v in d.items()]
[['apple', 50, 60, 7, 12], ['orange', 70, 50, 8]]

然而,这并没有给出总和。它可以通过以下方式轻松修复:

print [list(k)+[sum(v)] for k,v in d.items()]

没有太多理由比 Martijn 更优雅的解决方案更喜欢这个,除了它允许用户有一个包含超过 4 个项目的输入列表(后面的元素按预期求和)。换句话说,这将通过列表:

a_list = [['apple', 50, 60, 7, 12],
          ['orange', 70, 50, 8]]

也是。

于 2013-01-23T21:05:10.567 回答
0

形成密钥,[:3]以便获得前 3 个元素。

于 2013-01-23T21:03:46.980 回答