如何在一个任意的ord中pythonically迭代两个列表

2024-04-19 18:01:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我想迭代两个列表,这样我就可以从一个列表中获取任意数量的值,并保持我在另一个列表中的位置。你知道吗

我已经使用索引来存储每个列表中的当前位置,然后使用一个while循环来遍历它们,但这绝对不是什么好东西。你知道吗

def alternate_iterate(a,b,cond=lambda x, y : x > y):
    pos_a = 0
    pos_b = 0
    retval = []

    while(True):

        if(pos_a == len(a) and pos_b == len(b)):
            break

        if(pos_a < len(a) and cond(a[pos_a],b[pos_b])):
            retval += [a[pos_a]]
            pos_a += 1
        elif(pos_b < len(b)):
            retval += [b[pos_b]]
            pos_b += 1

    return retval

#example usage
print(alternate_iterate(['abc','abcd','ab','abc','ab'],
                        ['xy','xyz','x','xyz'],
                        cond=lambda x,y: len(x) > len(y))

这应该打印['abc','abdc','xy','xyz','ab','abc','ab','x','xyz'],这里没有完美的1:1交替顺序。元素的顺序和类型只应取决于cond的定义。你知道吗


Tags: andlambdapos列表lenifababc
3条回答

此版本仅使用迭代器以惰性方式实现功能(这是Pythonic):

a = ['abc','abcd','ab','abc','ab']
b = ['xy','xyz','x','xyz']

cond=lambda x,y: len(x) > len(y)

def alternate_iterate(a, b, cond):
    a, b = iter(a), iter(b)

    def _return_rest():
        def _f(val, it):
            yield val
            yield from it
        return _f

    v1, v2 = next(a, _return_rest), next(b, _return_rest)

    while True:
        if v1 is _return_rest:
            yield from v1()(v2, b)
            break

        if v2 is _return_rest:
            yield from v2()(v1, a)
            break

        if cond(v1, v2):
            yield v1
            v1 =  next(a, _return_rest)
        else:
            yield v2
            v2 = next(b, _return_rest)

print(list(alternate_iterate(a, b, cond)))

印刷品:

['abc', 'abcd', 'xy', 'xyz', 'ab', 'abc', 'ab', 'x', 'xyz']

更具python风格的方法通常是根本不使用索引,最好不要使用异常作为控制“预期”程序逻辑的手段。你也应该避免不必要的括号。你知道吗

下面是如何使用迭代器:

def merge(a, b, cond=lambda x, y : x < y):
    Done           = []
    iterA, iterB   = iter(a), iter(b)
    valueA, valueB = next(iterA, Done), next(iterB, Done)
    result         = []
    while not(valueB is Done and valueA is Done):
        if valueB is Done or valueA is not Done and cond(valueA, valueB):
            result.append(valueA)
            valueA = next(iterA, Done)
        else:
            result.append(valueB)
            valueB = next(iterB, Done)
    return result

这样做还有一个额外的好处,就是使函数能够有效地使用任何可编辑的数据作为参数。你知道吗

例如:

print(merge(range(5, 10), range(7, 15)))

# [5, 6, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13, 14]

它还可以方便地为延迟遍历创建迭代器版本的函数:

def iMerge(a, b, cond=lambda x, y : x < y):
    Done           = []
    iterA, iterB   = iter(a), iter(b)
    valueA, valueB = next(iterA, Done), next(iterB, Done)
    while not(valueB is Done and valueA is Done):
        if valueB is Done or valueA is not Done and cond(valueA, valueB):
            yield valueA
            valueA = next(iterA ,Done)
        else:
            yield valueB
            valueB = next(iterB, Done)

编辑None更改为Done,以使函数支持None作为输入列表中的合法值。你知道吗

欢迎使用Stackoverflow。总之,您似乎希望根据某个谓词的值从一个列表或另一个列表中获取一个值。您现有的逻辑似乎没有考虑其中一个列表用尽的可能性,此时我假设您希望从另一个列表复制任何剩余的值。你知道吗

您可以在列表上构建迭代器,并使用next函数获取下一个值,而不是使用索引值来选择连续的列表元素。你知道吗

在这种情况下,你的逻辑最终会变成这样:

def alternate_iterate(a_lst, b_lst, cond=lambda x, y: x > y):
    a_iter = iter(a_lst)
    b_iter = iter(b_lst)
    a = next(a_iter)
    b = next(b_iter)
    ret = []
    while True:
        if cond(a, b):
            ret.append(a)
            try:
                a = next(a_iter)
            except StopIteration:
                ret.append(b)
                for x in b_iter:
                    ret.append(x)
                return ret
        else:
            ret.append(b)
            try:
                b = next(b_iter)
            except StopIteration:
                ret.append(a)
                for x in a_iter:
                    ret.append(x)
                return ret


print(alternate_iterate(['abc','abcd','ab','abc','ab'],
                        ['xy','xyz','x','xyz'],
                        cond=lambda x,y: len(x) > len(y)))

我得到的结果是

['abc', 'abcd', 'xy', 'xyz', 'ab', 'abc', 'ab', 'x', 'xyz']

这似乎是你所期望的。你知道吗

像这样的例子中经常出现的情况一样,您编写更多的逻辑来处理更为罕见的情况(在本例中,一个列表或另一个列表变得筋疲力尽),而不是处理事情正常进行的“快乐之路”。你知道吗

相关问题 更多 >