我有一份清单清单。如果存在共有前三个元素的子列表,请将它们合并到一个列表中并添加所有第四个元素。
最好在代码和所需输出中解释问题。
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]]
如何修改代码以适应我的新问题?如果您也能花时间并彻底解释代码,我真的很感激。
答案 0 :(得分: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()]
因为您可以使用starred target从列表中获取所有“剩余”值,因此每个子列表主要分配给key
,最后一个值分配给v
,循环只是那么简单(并且在Python 3中的dict上没有.iteritems()
方法,因为.items()
已经是迭代器了。)
因此,我们使用defaultdict
使用0
作为默认值,然后使用前3个值生成的每个键(作为元组,以便将其用作字典键)总和最后一个值。
因此,对于第一项['apple', 50, 60, 7]
,我们创建了一个密钥('apple', 50, 60)
,在d
中查找它(它不存在,但defaultdict
将然后使用int()
创建新值0
),并添加第一项中的7
。
对('orange', 70, 50)
键和值8
执行相同操作。
对于第3项,我们再次获得('apple', 50, 60)
密钥,并将12
添加到7
中预先存在的d[('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))]
表示相同的输出。如果您的数据没有排序,这将会变慢,但了解不同的方法会很好。
答案 1 :(得分: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()]
除了允许用户拥有超过4个项目的输入列表(后面的元素按预期汇总)之外,没有太多理由比Martijn更优雅的解决方案更喜欢这个。 。换句话说,这将通过列表:
a_list = [['apple', 50, 60, 7, 12],
['orange', 70, 50, 8]]
。
答案 2 :(得分:0)
从[:3]
形成密钥,以便获得前3个元素。