gpt4 book ai didi

python - Itertools zip_longest 将每个子列表的第一项作为填充值而不是默认情况下的 None

转载 作者:行者123 更新时间:2023-12-04 15:28:50 28 4
gpt4 key购买 nike

我有这个列表列表:

cont_det = [['TASU 117000 0', "TGHU 759933 - 0", 'CSQU3054383', 'BMOU 126 780-0', "HALU 2014 13 3"], ['40HS'], ['Ha2ardous Materials', 'Arm5 Maehinery']]

实际 cont_det是一个巨大的列表,有很多子列表,每个子列表的长度不规则。这只是用于演示的示例案例。我想获得以下输出:
[['TASU 117000 0', '40HS', 'Ha2ardous Materials'], 
['TGHU 759933 - 0', '40HS', 'Arm5 Maehinery'],
['CSQU3054383', '40HS', 'Ha2ardous Materials'],
['BMOU 126 780-0', '40HS', 'Ha2ardous Materials'],
['HALU 2014 13 3', '40HS', 'Ha2ardous Materials']]

这背后的逻辑是 zip_longest列表列表,但如果有任何子列表的长度小于子列表所有长度的最大值(第一个子列表在这里为 5),则代替默认值 fillvalue=None取该子列表的第一项 - 如在第二个子列表的情况下所见,所有反射(reflect)的填充值都相同,对于第三个,最后三个由第一个值填充。

我用这段代码得到了结果:
from itertools import zip_longest as zilo
from more_itertools import padded as pad
max_ = len(max(cont_det, key=len))
for i, cont_row in enumerate(cont_det):
if len(cont_det)!=max_:
cont_det[i] = list(pad(cont_row, cont_row[0], max_))
cont_det = list(map(list, list(zilo(*cont_det))))

这给了我预期的结果。相反,我做了 list(zilo(*cont_det, fillvalue=''))我会得到这个:
[('TASU 117000 0', '40HS', 'Ha2ardous Materials'), 
('TGHU 759933 - 0', '', 'Arm5 Maehinery'),
('CSQU3054383', '', ''),
('BMOU 126 780-0', '', ''),
('HALU 2014 13 3', '', '')]

是否有任何其他过程(例如映射任何函数等)到参数 fillvaluezip_longest函数,这样我就不必遍历列表来将每个子列表填充到最长子列表的长度之前,并且这件事可以在一行中完成 zip_longest ?

最佳答案

您可以通过 next 查看每个迭代器为了提取第一项(“头”),然后创建一个 sentinel标记迭代器结束的对象,最后 chain 一切以下列方式重新组合在一起:head -> remainder_of_iterator -> sentinel -> it.repeat(head) .

这使用 it.repeat 一旦到达迭代器的末尾,无限重播第一个项目,因此我们需要引入一种方法来在最后一个迭代器到达其 sentinel 时停止该过程。目的。为此,我们可以 (ab) 使用 map 的事实。如果映射函数引发(或泄漏)StopIteration,则停止迭代,例如来自 next 在已经耗尽的迭代器上调用。或者,我们可以使用 iter 的 2 参数形式停在 sentinel对象(见下文)。

所以我们可以将链式迭代器映射到一个函数上,该函数检查每个项目是否is sentinel并执行以下步骤:

  • if item is sentinel然后使用一个专用迭代器,通过 next 产生的项目少于迭代器的总数(因此泄漏 StopIteration 作为最后一个哨兵)并替换 sentinel与相应的 head .
  • else只需返回原始项目。

  • 最后我们可以只 zip 迭代器一起 - 它将在最后一个击中其 sentinel 时停止对象,即执行“zip-longest”。

    总之,以下函数执行上述步骤:
    import itertools as it


    def solution(*iterables):
    iterators = [iter(i) for i in iterables] # make sure we're operating on iterators
    heads = [next(i) for i in iterators] # requires each of the iterables to be non-empty
    sentinel = object()
    iterators = [it.chain((head,), iterator, (sentinel,), it.repeat(head))
    for iterator, head in zip(iterators, heads)]
    # Create a dedicated iterator object that will be consumed each time a 'sentinel' object is found.
    # For the sentinel corresponding to the last iterator in 'iterators' this will leak a StopIteration.
    running = it.repeat(None, len(iterators) - 1)
    iterators = [map(lambda x, h: next(running) or h if x is sentinel else x, # StopIteration causes the map to stop iterating
    iterator, it.repeat(head))
    for iterator, head in zip(iterators, heads)]
    return zip(*iterators)

    如果泄漏 StopIteration从映射函数以终止 map iterator 觉得太别扭那么我们可以稍微修改一下 running 的定义产生额外的 sentinel并使用 iter 的 2 参数形式为了停在 sentinel :
    running = it.chain(it.repeat(None, len(iterators) - 1), (sentinel,))
    iterators = [...] # here the conversion to map objects remains unchanged
    return zip(*[iter(i.__next__, sentinel) for i in iterators])

    如果名称解析为 sentinelrunning从映射函数内部是一个问题,它们可以作为该函数的参数包含在内:
    iterators = [map(lambda x, h, s, r: next(r) or h if x is s else x,
    iterator, it.repeat(head), it.repeat(sentinel), it.repeat(running))
    for iterator, head in zip(iterators, heads)]

    关于python - Itertools zip_longest 将每个子列表的第一项作为填充值而不是默认情况下的 None,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59275346/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com