1

我想知道是否有办法将列表中“不匹配”项的默认值设置为 izip_longtest 函数中的最新值。

问题:我有一个单词,它在 x、y 和旋转上有一个位置。这些可以是多个,并且单词的每个字母都必须有位置/旋转。

更明确地说:我有两个列表:

  • 第一个本身就是一个元组 (x, y, r),它们是匹配字母的位置和旋转。
  • 第二个是匹配位置/旋转的字符。

例如,如果我有单词“HELLO”和x = [1,2,3,4,5]y = [6,7,8,9,10]r = [11,12,13,14,15]

'H' 字母将具有x = 1, y = 6,y = 11 最后一个字母 'O' 将具有x = 5, y = 10,r = 15

但是,如果单词是 "PROBLEM" and x = [1],则只有 'P' 字母会匹配 x 值,而所有其他字母都将设置为Nonewith izip_longest

我想要的是“传播”最新的或只有一个x到所有其他字母。所以,请,如果您有任何建议或解决方案,请告诉我。提前感谢!

4

4 回答 4

1

正如您所注意到的,izip_longest它并没有完全带您到那里。但是,您可以将其包裹起来,然后将其穿过终点线。

def izip_longest_last_value(*args, **kwargs):
    last = (None,) * len(args)
    for x in izip_longest(*args, **kwargs):
        last = tuple(z if z is not None else last[y] for y,z in enumerate(x))
        yield last

izip_longest有一个 *args, **kwargs 的签名,所以我们在这里重复。我们还支持任意数量的位置参数,因此您可以将 1、2 或 46 个不同的列表压缩在一起。

我们将 last 初始化为一个元组,只要位置参数的数量。Last 将被更新以包含上次迭代的值。

for x in izip_longest()我们是否从 izip_longest(包装器的肉)中获取当前值。

last = tuple(...)我们是否更新最后一个元组,并填充来自 izip 的当前值或来自 last 的值,如果为空间izip_longest返回 a None,则表明它已被填充。

于 2016-04-30T00:04:21.700 回答
0

由于默认设置zip_longest不适合您,因此这里有一个更智能的版本:

import pprint
word = 'PROBLEM'

def zip_longest(*iterators):
    last = {}
    # Make a list of non-empty iterators
    non_empty = dict.fromkeys(range(len(iterators)))

    # Make sure it's an iterator, does no harm on iterators and helps
    # on lists
    iterators = map(iter, iterators)
    while non_empty:
        # Prepare the row
        row = []

        # Walk through the iterators in the given order
        for i, iterator in enumerate(iterators):
            # If there are still values, find the next
            if i in non_empty:
                try:
                    last[i] = iterator.next()
                except StopIteration:
                    # No items anymore, this one is empty
                    del non_empty[i]

            # Add the current (or last if it was already empty) value
            row.append(last.get(i))

        yield row

第一个/简单测试:

x = [1]
y = [2]
pprint.pprint(list(zip_longest(word, x, y)))
[['P', 1, 2],
 ['R', 1, 2],
 ['O', 1, 2],
 ['B', 1, 2],
 ['L', 1, 2],
 ['E', 1, 2],
 ['M', 1, 2],
 ['M', 1, 2]]

稍微复杂一点:

x = range(3)
y = range(6)
pprint.pprint(list(zip_longest(word, x, y)))
[['P', 0, 0],
 ['R', 1, 1],
 ['O', 2, 2],
 ['B', 2, 3],
 ['L', 2, 4],
 ['E', 2, 5],
 ['M', 2, 5],
 ['M', 2, 5]]

对于其他更长的范围:

x = range(10)
y = range(5)
pprint.pprint(list(zip_longest(word, x, y)))

[['P', 0, 0],
 ['R', 1, 1],
 ['O', 2, 2],
 ['B', 3, 3],
 ['L', 4, 4],
 ['E', 5, 4],
 ['M', 6, 4],
 ['M', 7, 4],
 ['M', 8, 4],
 ['M', 9, 4],
 ['M', 9, 4]]

为了完整性:

x = []
y = []
pprint.pprint(list(zip_longest(word, x, y)))

[['P', None, None],
 ['R', None, None],
 ['O', None, None],
 ['B', None, None],
 ['L', None, None],
 ['E', None, None],
 ['M', None, None],
 ['M', None, None]]
于 2013-08-14T14:39:56.217 回答
0

您可能需要自己的自定义zip迭代器。主要基于但对最后一个值izip_longest有一些记忆。not None

可能还有改进的余地,但这里的精神是:

import itertools

def myzip(it1, it2):
    last1 = None
    last2 = None
    for i in itertools.izip_longest(it1, it2):
        if i[0] is not None:
            last1 = i[0]
        if i[1] is not None:
            last2 = i[1]
        yield((last1, last2))

这是“测试用例”:

>>> lst1 = ('a', 'b')
>>> lst2 = (1,2,3,4,5)

>>> print list(myzip(lst1, lst2))
[('a', 1), ('b', 2), ('b', 3), ('b', 4), ('b', 5)]

>>> print list(myzip(lst2, lst1))
[(1, 'a'), (2, 'b'), (3, 'b'), (4, 'b'), (5, 'b')]
于 2013-08-14T14:50:15.487 回答
0

用于itertools.cycle()较短的输入,不要使用izip_longest()

from itertools import cycle, izip

izip(word, cycle(x), cycle(y), cycle(r))

现在xyr将循环通过以匹配 中的其余字符word

>>> list(zip(word, cycle(x), cycle(y), cycle(r)))
[('P', 1, 6, 11), ('R', 2, 7, 12), ('O', 3, 8, 13), ('B', 4, 9, 14), ('L', 5, 10, 15), ('E', 1, 6, 11), ('M', 2, 7, 12)]
于 2013-08-14T15:14:04.080 回答