当前位置: 首页 > 知识库问答 >
问题:

zip_始终是左边列表中最长的

袁枫涟
2023-03-14

我知道zip函数(它将根据最短列表进行压缩)和zip_longest(它将根据最长列表进行压缩),但我如何根据第一个列表进行压缩,无论它是否最长?

例如:

Input:  ['a', 'b', 'c'], [1, 2]
Output: [('a', 1), ('b', 2), ('c', None)]

而且:

Input:  ['a', 'b'], [1, 2, 3]
Output: [('a', 1), ('b', 2)]

这两种功能是否都存在于一个功能中?

共有3个答案

尹正奇
2023-03-14

让第二个无限大,然后使用普通拉链:

from itertools import chain, repeat

a = ['a', 'b', 'c']
b = [1, 2]

b = chain(b, repeat(None))

print(*zip(a, b))
叶冥夜
2023-03-14

您可以重新利用itertools文档中显示的“大致相当”的python代码。zip_longest根据第一个参数的长度制作一个通用版本:

from itertools import repeat

def zip_by_first(*args, fillvalue=None):
    # zip_by_first('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
    # zip_by_first('ABC', 'xyzw', fillvalue='-') --> Ax By Cz
    if not args:
        return
    iterators = [iter(it) for it in args]
    while True:
        values = []
        for i, it in enumerate(iterators):
            try:
                value = next(it)
            except StopIteration:
                if i == 0:
                    return
                iterators[i] = repeat(fillvalue)
                value = fillvalue
            values.append(value)
        yield tuple(values)

您也许可以做一些小的改进,比如缓存重复(fillvalue)之类的。这个实现的问题是它是用Python编写的,而大多数iterool使用的是更快的C实现。通过与Kelly Bundy的答案进行比较,您可以看到这一点的效果。

江宏放
2023-03-14

将重复的fillvalue链接到iterables后面,而不是第一个:

from itertools import chain, repeat

def zip_first(first, *rest, fillvalue=None):
    return zip(first, *map(chain, rest, repeat(repeat(fillvalue))))

或者使用zip_longest并用压缩zip技巧修剪它:

def zip_first(first, *rest, fillvalue=None):
    a, b = tee(first)
    return compress(zip_longest(b, *rest, fillvalue=fillvalue), zip(a))

就像zipzip_longest一样,它们接受任何类型的iterables(包括无限个)中的任意数(至少一个),并返回一个迭代器(如果需要,转换为list)。

与其他同样通用的解决方案的基准:

10 iterables of 10,000 to 90,000 elements, first has 50,000:
------------------------------------------------------------
 49.9 ms   50.1 ms   50.4 ms  CrazyChucky
 74.3 ms   74.6 ms   75.1 ms  Mad_Physicist
  2.5 ms    2.6 ms    2.6 ms  Kelly_Bundy_chain
  3.2 ms    3.2 ms    3.3 ms  Kelly_Bundy_compress
  5.2 ms    5.3 ms    5.3 ms  Kelly_Bundy_3
  5.9 ms    6.0 ms    6.0 ms  Kelly_Bundy_4
  4.5 ms    4.6 ms    4.6 ms  Kelly_Bundy_5
  2.3 ms    2.3 ms    2.3 ms  limit_cheat

20,000 iterables of 0 to 100 elements, first has 50:
----------------------------------------------------
 54.8 ms   55.6 ms   56.2 ms  CrazyChucky
164.1 ms  165.4 ms  165.7 ms  Mad_Physicist
 18.6 ms   18.9 ms   19.0 ms  Kelly_Bundy_chain
 11.1 ms   11.1 ms   11.1 ms  Kelly_Bundy_compress
 11.2 ms   11.3 ms   11.4 ms  Kelly_Bundy_3
 11.6 ms   11.6 ms   11.8 ms  Kelly_Bundy_4
 11.6 ms   11.8 ms   11.8 ms  Kelly_Bundy_5
 10.8 ms   10.9 ms   10.9 ms  limit_cheat

最后一个是一个知道长度的作弊,包括显示我们能以多快的速度到达的极限。

基准代码(在线试用!):

def CrazyChucky(*iterables, fillvalue=None):
    SENTINEL = object()
    
    for first, *others in zip_longest(*iterables, fillvalue=SENTINEL):
        if first is SENTINEL:
            return
        others = [i if i is not SENTINEL else fillvalue for i in others]
        yield (first, *others)

def Mad_Physicist(*args, fillvalue=None):
    # zip_by_first('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
    # zip_by_first('ABC', 'xyzw', fillvalue='-') --> Ax By Cz
    if not args:
        return
    iterators = [iter(it) for it in args]
    while True:
        values = []
        for i, it in enumerate(iterators):
            try:
                value = next(it)
            except StopIteration:
                if i == 0:
                    return
                iterators[i] = repeat(fillvalue)
                value = fillvalue
            values.append(value)
        yield tuple(values)

def Kelly_Bundy_chain(first, *rest, fillvalue=None):
    return zip(first, *map(chain, rest, repeat(repeat(fillvalue))))

def Kelly_Bundy_compress(first, *rest, fillvalue=None):
    a, b = tee(first)
    return compress(zip_longest(b, *rest, fillvalue=fillvalue), zip(a))

def Kelly_Bundy_3(first, *rest, fillvalue=None):
    a, b = tee(first)
    return map(itemgetter(1), zip(a, zip_longest(b, *rest, fillvalue=fillvalue)))

def Kelly_Bundy_4(first, *rest, fillvalue=None):
    sentinel = object()
    for z in zip_longest(chain(first, [sentinel]), *rest, fillvalue=fillvalue):
        if z[0] is sentinel:
            break
        yield z

def Kelly_Bundy_5(first, *rest, fillvalue=None):
    stopped = False
    def stop():
        nonlocal stopped
        stopped = True
        return
        yield
    for z in zip_longest(chain(first, stop()), *rest, fillvalue=fillvalue):
        if stopped:
            break
        yield z

def limit_cheat(*iterables, fillvalue=None):
    return islice(zip_longest(*iterables, fillvalue=fillvalue), 50_000)


import timeit
from itertools import chain, repeat, zip_longest, islice, tee, compress
from operator import itemgetter
from collections import deque

funcs = [
    CrazyChucky,
    Mad_Physicist,
    Kelly_Bundy_chain,
    Kelly_Bundy_compress,
    Kelly_Bundy_3,
    Kelly_Bundy_4,
    Kelly_Bundy_5,
    limit_cheat,
]

def args():
    first = repeat(0, 50_000)
    rest = [repeat(i, 10_000 * i) for i in range(1, 10)]
    return first, *rest

def args2():
    first = repeat(0, 50)
    rest = [repeat(i, i % 101) for i in range(1, 20_000)]
    return first, *rest

expect = list(funcs[0](*args()))
for func in funcs:
    result = list(func(*args()))
    print(result == expect, func.__name__)
    
for _ in range(3):
    print()
    for func in funcs:
        times = timeit.repeat(lambda: deque(func(*args()), 0), number=1)
        print(*('%4.1f ms ' % (t * 1e3) for t in sorted(times)[:3]), func.__name__)
 类似资料:
  • 问题内容: 获取最长单词长度的更Python方式是什么: 要么: 或者是其他东西? 是字符串列表。我发现我经常需要这样做,并且在用几个不同的样本量进行计时之后,第一种方法似乎始终如一地更快,尽管在票面价值上似乎效率不高(被叫两次的冗余似乎无关紧要,在第二种方法中发生的更多)这种形式的C代码?)。 问题答案: 我认为两者都可以,但是我认为除非速度是最易读的大考虑。 当我看着它们时,我花了更长的时间才

  • 问题内容: 我有两张桌子。我想以一种方式将它们加入,即最左侧表中的每个记录只返回右侧表中的一个记录。我在下面提供了一个示例。我想避免使用子查询和临时表,因为实际数据约为4M行。我也不在乎最右边表中的哪条记录被匹配,只要一个或一个都不匹配即可。谢谢! 表用户: 表交易: 预期输出: 问题答案: 使用: 请注意,这只会返回至少具有一个TRANSACTIONS记录的用户。如果要查看没有支持记录的用户以及

  • 问题内容: 我正在做一个从列表中返回最长字符串值的函数。当只有一个包含最多字符的字符串时,我的代码有效。如果有多个字符串,我尝试使其打印所有最长的字符串,并且我不希望重复它们。当我运行它时,它只返回“ hello”,而我希望它也返回“ ohman”和“ yoloo”。我觉得问题就在眼前,但是我已经尝试了所有方法,但是没有用。 问题答案: 首先 ,我们可以在列表中找到任何字符串的最大长度: 一点解释

  • 我尝试通过像这样更改if语句来只获得最长的回文。 这并不像预期的那样有效。我只打印第一个回文[“w”],然后在列表中返回整个字符串[“w”,“h”,...]

  • 问题内容: 可以从许多线程访问类。在这种情况下,必须是记录器还是最终的和静态的?谢谢。 问题答案: 所有主要的Java日志记录程序包(等)都是同步的并且是线程安全的。即使从多个线程调用该类,每个类的记录器的标准模式也可以。

  • 问题内容: python中是否有内置函数返回两个列表的最长公共子序列的长度? 我试图找到最长的公共子序列,然后得到它的长度,但是我认为必须有一个更好的解决方案。 问题答案: 您可以轻松地将LCS重新装配为LLCS: 演示: 如果您想要最长的公共 子字符串 (一个 不同 但相关的问题, 子 序列是连续的),请使用: 这与动态编程方法非常相似,但是我们跟踪到目前为止找到的最大长度(因为不再保证表中的最