提问人:Wör Du Schnaffzig 提问时间:8/28/2023 最后编辑:Wör Du Schnaffzig 更新时间:8/28/2023 访问量:56
具有可变填充值的 Python itertools.zip_longest
Python itertools.zip_longest with mutable fillvalue
问:
在评估 Web 响应的代码中,我想从多个列表中压缩元素。但是,迭代器的元素是 的。
因此,我也想用 's 填充缺失值,但每个生成的元素都应该有自己的实例。dict
dict
dict
以下代码按 对每个列表中的元素进行分组。
只要指定了不可变,就没有问题。itertools.zip_longest
fillvalue
import collections
import itertools
l1 = [{"a": 100}, {"b": 200}, {"c": 300}]
l2 = [{"d": 400}]
ll = list(itertools.zip_longest(l1, l2, fillvalue=0))
print(ll)
-> [({'a': 100}, {'d': 400}), ({'b': 200}, 0), ({'c': 300}, 0)]
现在,当指定一个可变对象时,所有 共享同一个实例,因此更改一个实例会更改所有实例:fillvalue
fillvalue
import collections
import itertools
l1 = [{"a": 100}, {"b": 200}, {"c": 300}]
l2 = [{"d": 400}]
ll = list(itertools.zip_longest(l1, l2, fillvalue=dict()))
ll[1][1]["x"] = 150
print(ll)
-> [({'a': 100}, {'d': 400}), ({'b': 200}, {'x': 150}), ({'c': 300}, {'x': 150})]
为了防止所有字典共享相同的实例,我使用了:copy.deepcopy
import collections
import copy
import itertools
l1 = [{"a": 100}, {"b": 200}, {"c": 300}]
l2 = [{"d": 400}]
ll = list(itertools.zip_longest(l1, l2, fillvalue=copy.deepcopy(dict())))
ll[1][1]["x"] = 150
print(ll)
-> [({'a': 100}, {'d': 400}), ({'b': 200}, {'x': 150}), ({'c': 300}, {'x': 150})]
因此,仍然所有 的 共享同一个实例。dict
fillvalue
我想补充一点,假设填充值为 。ll = [item or dict() for item in itertools.zip_longest(l1, l2)]
None
那么,我怎样才能让每个都独一无二呢?fillvalue
答:
你不能教你复制 s。您必须自己复制它们(这也将使原始值与 ),例如:zip_longest
dict
l2
ll = [(d1, d2.copy()) for d1, d2 in itertools.zip_longest(l1, l2, fillvalue={})]
或者只是按需从头开始制作它们(这将把空 s 与 分离,留下其余的别名,这可能是也可能不是你想要的):dict
l2
ll = [(d1, d2 or {}) for d1, d2 in itertools.zip_longest(l1, l2)]
完美保留混叠的替代方案是更冗长的:
ll = [(d1, {} if d2 is None else d2) for d1, d2 in itertools.zip_longest(l1, l2)]
如果可能短于 ,则在每个 listcomp 中应用类似的转换。l1
l2
d1
评论
fillvalue
l1
l2
None
dict
ll
l2
copy.deepcopy((l1, l2))
dict
dict
None
可以使用 sentinel 值并包装在另一个管道中。zip_longest
例如:
sentinel = object()
l = list(tuple({} if x is sentinel else x for x in items) for items in zip_longest(l1, l2, fillvalue=sentinel))
对于此示例,您可能可以使用而不是自定义对象。None
sentinel
评论
None
fillvalue
l = list(tuple(x if x is not None else {} for x in items) for items in zip_longest(l1, l2))
{} if x is None else x
享受更多迭代工具的乐趣,将 dict-producer 链接到列表中。这会将每个列表变成其元素的迭代器,然后是无限多的新空字典。压缩它们会得到所需的结果,但它不会在使用所有列表元素时停止。因此,我习惯于为我提供所需长度的迭代器,并使用该迭代器(in )来限制数据。zip_longest
compress
from itertools import starmap, chain, repeat, compress, zip_longest
l1 = [{"a": 100}, {"b": 200}, {"c": 300}]
l2 = [{"d": 400}]
lists = l1, l2
dicts = starmap(dict, repeat(()))
ll = list(compress(
zip(*map(chain, lists, repeat(dicts))),
zip_longest(*lists)
))
ll[1][1]['e'] = 500
print(ll)
输出(在线尝试!
[({'a': 100}, {'d': 400}),
({'b': 200}, {'e': 500}),
({'c': 300}, {})]
或者,用于在最大长度处停止:islice
ll = list(islice(
zip(*map(chain, lists, repeat(dicts))),
max(map(len, lists))
))
评论
len()
下一个:python 函数缓存可变结果
评论