如何以任意顺序对两个列表进行pythonical迭代
我想迭代两个列表,这样我可以从一个列表中获取任意数量的值,并在另一个列表中保持我的位置 我使用索引来存储每个列表中的当前位置,然后使用while循环来遍历它们,但这肯定不是很符合python如何以任意顺序对两个列表进行pythonical迭代,python,list,iterable,Python,List,Iterable,我想迭代两个列表,这样我可以从一个列表中获取任意数量的值,并在另一个列表中保持我的位置 我使用索引来存储每个列表中的当前位置,然后使用while循环来遍历它们,但这肯定不是很符合python def alternate\u iterate(a,b,cond=lambda x,y:x>y): 位置a=0 位置b=0 retval=[] 虽然(正确): 如果(pos_a==len(a)和pos_b==len(b)): 打破 如果(位置a
def alternate\u iterate(a,b,cond=lambda x,y:x>y):
位置a=0
位置b=0
retval=[]
虽然(正确):
如果(pos_a==len(a)和pos_b==len(b)):
打破
如果(位置alen(y))
这应该打印
['abc'、'abdc'、'xy'、'xyz'、'ab'、'abc'、'ab'、'x'、'xyz']
,其中没有完美的1:1交替顺序。元素的顺序和元素的类型应该只取决于cond
的定义。将列表放入生成器中,然后您可以对每个列表调用next
,以获得下一个值。这个答案并不意味着是一个完整的解决方案,just显示生成器如何使用非常简单的Python代码以任意顺序生成值:
agen = iter(a)
bgen = iter(b)
print next(agen) # 'a'
print next(bgen) # 1
print next(bgen) # 2
print next(agen) # 'b'
等等。欢迎使用Stackoverflow。概括起来,您似乎希望根据某个谓词的值从一个列表或另一个列表中获取一个值。您现有的逻辑似乎没有考虑其中一个列表被耗尽的可能性,在这一点上,我假设您希望从t复制任何剩余的值他还列出了其他清单 您可以在列表上构建迭代器,并使用
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']
这似乎是你所期望的
与此类示例中经常出现的情况一样,您编写更多的逻辑来处理更为罕见的情况(在本例中,一个列表或另一个列表将耗尽),而不是处理正常情况下进行的“快乐路径”。此版本仅使用迭代器惰性地实现功能(这是Pythonic): 印刷品:
['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
它还可以轻松创建用于延迟遍历的函数的迭代器版本:
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)
def iMerge(a,b,cond=lambda x,y:x
EDIT将
None
更改为Done
,以使函数支持None作为输入列表中的合法值。由于您没有通过f
为名称a
指定值,因此需要花费大量精力才能确定您在此处真正需要什么。是的a
的值是什么>,它们可以是类似于'a'
的字符串,因为您正在比较字符串和整数(在python 3中不可能)。我重新打开了它,因为我相信cond
函数可能会改变所需的解决方案(但如果没有说明,它可能会再次关闭)另外,语句b+=1
可能会带来麻烦,因为b是一个列表,因此当您尝试递增它时,这将导致类型错误。与a+=1
类似。我怀疑它们应该对相应的pos.*
名称进行操作。这忽略了该条件,远远不能生成输出列表。zip(agen,bgen)
将是朝着这个方向迈出的一步,但它本身还不够,它并不意味着是一个完整的解决方案,只是一个生成器按照正确的顺序生成值的演示,没有任何额外的索引变量。事实并非如此,这就是为什么它真的应该是一个注释。回答很好。下一步(iterA,完成)
是对next()
的一个鲜为人知的第二个参数的一个特别好的使用。在我看来,该函数的迭代器版本应该更突出;迭代器比返回合并列表的函数更适合打包此服务。更惯用的方法是,只使用普通对象,所以Done=object()
,虽然只要始终用于检查,列表就可以工作,但使用什么sentinel对象并不重要。使用iter
的第二个参数可以大大简化代码。确保sentinel不是可能的值之一很重要。这是通过使用对象实例cr实现的在函数中创建(完成)。我以前使用的是不符合该要求的None。
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)