如何从两端迭代一个序列?
How to iterate a sequence from both ends?
我想迭代(部分)Python 序列 "from both ends"(到(那部分的)中间,在这里)。
在 C/C++/Java 中,我可能会尝试
int start = 2, beyond = 7;
for (int forward = start, back = beyond ; forward <= --back ; forward++)
printf("%d %d\n", forward, back);
我似乎无法决定我最不喜欢以下哪个变体:
seq = tuple(chr(c) for c in range(ord('a'), ord('z')+1))
start, beyond = 2, 7
print("subtract")
for forward in range(start, beyond):
back = start + beyond - 1 - forward
if (back < forward):
break
print(seq[forward], seq[back])
# if (back <= forward): XXX ERROR, as YvesgereY pointed out
# break
print("reversed")
for forward, back in zip(range(start, beyond),
reversed(range(start, beyond))):
if (back < forward):
break
print(seq[forward], seq[back])
print("step -1")
for forward, back in zip(range(start, beyond), range(beyond-1, start-1, -1)):
if (back < forward):
break
print(seq[forward], seq[back])
print("naked code")
forward, back = start, beyond-1 # thanks again, YvesgereY
while (forward <= back):
print(seq[forward], seq[back])
forward += 1
back -= 1
是否有 pleasing/sane/idiomatic 方法来处理这个问题?
我宁愿写:
size = max((beyond-start+1)//2,0) # 0 if start>beyond
for i in range(0,size):
print(start+i,beyond-i-1)
请注意,您的 substract
和 step -1
版本不正确,因为它们在上一次迭代中允许 forward>back
。
您可以通过强调循环条件(降低差一错误的可能性)来稍微改进 while
版本:
forward, back = start, beyond-1
while forward <= back:
print(forward, back)
forward += 1
back -= 1
在我看来,最后一种使用while循环的方法是最好的:
forward, back = start, beyond
while (forward < back):
back -= 1
print(forward, back)
forward += 1
它简洁但仍然可读,语义清晰,与其他具有多层函数调用嵌套的方法相比,似乎是最'Pythonic'。您可以通过将其包装在生成器中来改进它:
def iterate_to_middle(start_front, start_end):
while start_front < start_end:
start_end -= 1
yield start_front, start_end
start_front += 1
然后可以这样使用:
>>> for indexes in iterate_to_middle(2, 7):
print(indexes)
(2, 6)
(3, 5)
(4, 4)
你可能想多了。 while
循环没问题。
此外,Python 中的序列类型支持 负索引 ,我认为这可以简化事情。这是一种使用 enumerate
为每个前向项生成负对应索引的方法:
lst = [1, 2, 3, 4, 5]
for i, x in enumerate(lst, 1):
print(x, lst[-i])
if i * 2 >= len(lst): break
(1, 5)
(2, 4)
(3, 3)
为什么不 zip
列表本身的反面?
mid = (len(lst) + 1) // 2
for x, y in zip(lst[:mid], lst[::-1]):
print((x, y))
(1, 5)
(2, 4)
(3, 3)
zip
自动处理不同长度的列表,只要确保你正确设置中点(这取决于列表大小是否均匀)。
您可以使用 ~ 运算符得到 (index + 1) * -1。
arr = [1, 2, 3, 4, 5]
for i in range((len(arr) + 1) // 2):
print(arr[i], arr[~i])
1 5
2 4
3 3
我想迭代(部分)Python 序列 "from both ends"(到(那部分的)中间,在这里)。
在 C/C++/Java 中,我可能会尝试
int start = 2, beyond = 7;
for (int forward = start, back = beyond ; forward <= --back ; forward++)
printf("%d %d\n", forward, back);
我似乎无法决定我最不喜欢以下哪个变体:
seq = tuple(chr(c) for c in range(ord('a'), ord('z')+1))
start, beyond = 2, 7
print("subtract")
for forward in range(start, beyond):
back = start + beyond - 1 - forward
if (back < forward):
break
print(seq[forward], seq[back])
# if (back <= forward): XXX ERROR, as YvesgereY pointed out
# break
print("reversed")
for forward, back in zip(range(start, beyond),
reversed(range(start, beyond))):
if (back < forward):
break
print(seq[forward], seq[back])
print("step -1")
for forward, back in zip(range(start, beyond), range(beyond-1, start-1, -1)):
if (back < forward):
break
print(seq[forward], seq[back])
print("naked code")
forward, back = start, beyond-1 # thanks again, YvesgereY
while (forward <= back):
print(seq[forward], seq[back])
forward += 1
back -= 1
是否有 pleasing/sane/idiomatic 方法来处理这个问题?
我宁愿写:
size = max((beyond-start+1)//2,0) # 0 if start>beyond
for i in range(0,size):
print(start+i,beyond-i-1)
请注意,您的 substract
和 step -1
版本不正确,因为它们在上一次迭代中允许 forward>back
。
您可以通过强调循环条件(降低差一错误的可能性)来稍微改进 while
版本:
forward, back = start, beyond-1
while forward <= back:
print(forward, back)
forward += 1
back -= 1
在我看来,最后一种使用while循环的方法是最好的:
forward, back = start, beyond
while (forward < back):
back -= 1
print(forward, back)
forward += 1
它简洁但仍然可读,语义清晰,与其他具有多层函数调用嵌套的方法相比,似乎是最'Pythonic'。您可以通过将其包装在生成器中来改进它:
def iterate_to_middle(start_front, start_end):
while start_front < start_end:
start_end -= 1
yield start_front, start_end
start_front += 1
然后可以这样使用:
>>> for indexes in iterate_to_middle(2, 7):
print(indexes)
(2, 6)
(3, 5)
(4, 4)
你可能想多了。 while
循环没问题。
此外,Python 中的序列类型支持 负索引 ,我认为这可以简化事情。这是一种使用 enumerate
为每个前向项生成负对应索引的方法:
lst = [1, 2, 3, 4, 5]
for i, x in enumerate(lst, 1):
print(x, lst[-i])
if i * 2 >= len(lst): break
(1, 5)
(2, 4)
(3, 3)
为什么不 zip
列表本身的反面?
mid = (len(lst) + 1) // 2
for x, y in zip(lst[:mid], lst[::-1]):
print((x, y))
(1, 5)
(2, 4)
(3, 3)
zip
自动处理不同长度的列表,只要确保你正确设置中点(这取决于列表大小是否均匀)。
您可以使用 ~ 运算符得到 (index + 1) * -1。
arr = [1, 2, 3, 4, 5]
for i in range((len(arr) + 1) // 2):
print(arr[i], arr[~i])
1 5
2 4
3 3