跳过枚举列表对象中的迭代 (python)
Skip iterations in enumerated list object (python)
我有密码
for iline, line in enumerate(lines):
...
if <condition>:
<skip 5 iterations>
如您所见,如果满足条件,我希望 for 循环跳过 5 次迭代。我可以确定,如果满足条件,"lines" 对象中还剩下 5 个或更多对象。
存在字典数组的行,必须按顺序循环
iline = 0
while iline < len(lines):
line = lines[iline]
if <condition>:
place_where_skip_happened = iline
iline += 5
iline += 1
如果您正在遍历文件对象,您可以使用 next 跳过行或将行设为迭代器:
lines = iter(range(20))
for l in lines:
if l == 10:
[next(lines) for _ in range(5)]
print(l)
0
1
2
3
4
5
6
7
8
9
10
16
17
18
19
这实际上取决于您要迭代的内容以及您想要执行的操作。
将您自己的代码与 iter and islice 一起使用:
from itertools import islice
it = iter(enumerate(lines))
for iline, line in it:
if <condition>:
place_where_skip_happened = iline
next(islice(it,5 ,5), None)
print(line)
正如 Padraic Cunningham 所说,您可以使用 while 循环来完成此操作,也可以使用字典来替换 if 语句:
iline = 0
skip = {True:5, False:1}
while iline > len(lines):
line = lines[iline]
...
iline += skip[condition]
执行此操作的标准习惯用法是制作一个迭代器,然后使用其中一种消费者模式(请参阅 itertools
文档中的 here。)
例如:
from itertools import islice
lines = list("abcdefghij")
lit = iter(enumerate(lines))
for iline, line in lit:
print(iline, line)
if line == "c":
# skip 3
next(islice(lit, 3,3), None)
产生
0 a
1 b
2 c
6 g
7 h
8 i
9 j
使用外部标志并在满足条件时设置它并在循环开始时检查它:
ignore = 0
for iline, line in enumerate(lines):
if ignore > 0:
ignore -= 1
continue
print(iline, line)
if iline == 5:
ignore = 5
或者显式地从枚举中提取 5 个元素:
enum_lines = enumerate(lines)
for iline, line in enum_lines:
print(iline, line)
if iline == 5:
for _, _ in zip(range(5), enum_lines):
pass
我个人更喜欢第一种方法,但第二种方法看起来更像 Pythonic。
您可以使用带递归的函数式编程风格,首先将 for
循环的必要部分放入函数中:
def my_function(iline, line, rest_of_lines, **other_args):
do_some_side_effects(iline, line, **other_args)
if rest_of_lines == []:
return <some base case>
increment = 5 if <condition> else 1
return my_function(iline+increment,
rest_of_lines[increment-1],
rest_of_lines[increment:],
**other_args)
可选地,如果不需要return任何东西,您可以将这些代码行调整为函数调用,return结果将是None
。
然后在某个地方你实际上称之为:
other_args = get_other_args(...)
my_function(0, lines[0], lines[1:], **other_args)
如果您需要函数 return 每个索引都有不同的东西,那么我建议稍微修改一下以说明您想要的输出数据结构。在这种情况下,您可能希望将 do_some_side_effects
的内部结果传递回递归函数调用,以便它可以构建结果。
def my_function(iline, line, rest_of_lines, output, **other_args):
some_value = do_some_side_effects(iline, line, **other_args)
new_output = put_value_in_output(some_value, output)
# could be as simple as appending to a list/inserting to a dict
# or as complicated as you want.
if rest_of_lines == []:
return new_output
increment = 5 if <condition> else 1
return my_function(iline+increment,
rest_of_lines[increment-1],
rest_of_lines[increment:],
new_output,
**other_args)
然后打电话
other_args = get_other_args(...)
empty_output = get_initial_data_structure(...)
full_output = my_function(0, lines[0], lines[1:], empty_output, **other_args)
请注意,在 Python 中,由于大多数基本数据结构的实现方式,这种编程风格不会提高您的效率,在其他面向对象代码的上下文中,它甚至可能是使事情复杂化的糟糕风格 while
解决方案。
我的建议:使用 while
循环,尽管我倾向于构建我的项目和 API,以便使用递归函数方法仍然高效且可读。我也会尽量不要在循环内产生副作用。
使用枚举索引
类似于已接受的答案……除了不使用 itertools
(恕我直言 islice
不会提高可读性),再加上 enumerate()
已经 returns 一个迭代器,所以你不需要根本不需要 iter()
:
lines = [{str(x): x} for x in range(20)] # dummy data
it = enumerate(lines)
for i, line in it:
print(line)
if i == 10: # condition using enumeration index
[next(it, None) for _ in range(5)] # skip 5
为了便于阅读,可以选择扩展最后一行:
for _ in range(5): # skip 5
next(it, None)
next()
中的 None
参数可避免在没有足够的项目可跳过时出现异常。 (对于原始问题,可以省略,如 OP 所写:"I can be sure that, if the condition is met, there are 5 or more objects left in the lines
object.")
没有使用枚举索引
如果跳过条件不是基于枚举索引,只需将列表视为 FIFO 队列并使用 pop()
:
从中使用
lines = [{str(x): x} for x in range(20)] # dummy data
while lines:
line = lines.pop(0) # get first item
print(line)
if <condition>: # some other kind of condition
[lines.pop(0) for _ in range(5)] # skip 5
和以前一样,为了便于阅读,可以选择扩展最后一行:
for _ in range(5): # skip 5
lines.pop(0)
(对于大型列表,使用 collections.deque
提高性能。)
我有密码
for iline, line in enumerate(lines):
...
if <condition>:
<skip 5 iterations>
如您所见,如果满足条件,我希望 for 循环跳过 5 次迭代。我可以确定,如果满足条件,"lines" 对象中还剩下 5 个或更多对象。
存在字典数组的行,必须按顺序循环
iline = 0
while iline < len(lines):
line = lines[iline]
if <condition>:
place_where_skip_happened = iline
iline += 5
iline += 1
如果您正在遍历文件对象,您可以使用 next 跳过行或将行设为迭代器:
lines = iter(range(20))
for l in lines:
if l == 10:
[next(lines) for _ in range(5)]
print(l)
0
1
2
3
4
5
6
7
8
9
10
16
17
18
19
这实际上取决于您要迭代的内容以及您想要执行的操作。
将您自己的代码与 iter and islice 一起使用:
from itertools import islice
it = iter(enumerate(lines))
for iline, line in it:
if <condition>:
place_where_skip_happened = iline
next(islice(it,5 ,5), None)
print(line)
正如 Padraic Cunningham 所说,您可以使用 while 循环来完成此操作,也可以使用字典来替换 if 语句:
iline = 0
skip = {True:5, False:1}
while iline > len(lines):
line = lines[iline]
...
iline += skip[condition]
执行此操作的标准习惯用法是制作一个迭代器,然后使用其中一种消费者模式(请参阅 itertools
文档中的 here。)
例如:
from itertools import islice
lines = list("abcdefghij")
lit = iter(enumerate(lines))
for iline, line in lit:
print(iline, line)
if line == "c":
# skip 3
next(islice(lit, 3,3), None)
产生
0 a
1 b
2 c
6 g
7 h
8 i
9 j
使用外部标志并在满足条件时设置它并在循环开始时检查它:
ignore = 0
for iline, line in enumerate(lines):
if ignore > 0:
ignore -= 1
continue
print(iline, line)
if iline == 5:
ignore = 5
或者显式地从枚举中提取 5 个元素:
enum_lines = enumerate(lines)
for iline, line in enum_lines:
print(iline, line)
if iline == 5:
for _, _ in zip(range(5), enum_lines):
pass
我个人更喜欢第一种方法,但第二种方法看起来更像 Pythonic。
您可以使用带递归的函数式编程风格,首先将 for
循环的必要部分放入函数中:
def my_function(iline, line, rest_of_lines, **other_args):
do_some_side_effects(iline, line, **other_args)
if rest_of_lines == []:
return <some base case>
increment = 5 if <condition> else 1
return my_function(iline+increment,
rest_of_lines[increment-1],
rest_of_lines[increment:],
**other_args)
可选地,如果不需要return任何东西,您可以将这些代码行调整为函数调用,return结果将是None
。
然后在某个地方你实际上称之为:
other_args = get_other_args(...)
my_function(0, lines[0], lines[1:], **other_args)
如果您需要函数 return 每个索引都有不同的东西,那么我建议稍微修改一下以说明您想要的输出数据结构。在这种情况下,您可能希望将 do_some_side_effects
的内部结果传递回递归函数调用,以便它可以构建结果。
def my_function(iline, line, rest_of_lines, output, **other_args):
some_value = do_some_side_effects(iline, line, **other_args)
new_output = put_value_in_output(some_value, output)
# could be as simple as appending to a list/inserting to a dict
# or as complicated as you want.
if rest_of_lines == []:
return new_output
increment = 5 if <condition> else 1
return my_function(iline+increment,
rest_of_lines[increment-1],
rest_of_lines[increment:],
new_output,
**other_args)
然后打电话
other_args = get_other_args(...)
empty_output = get_initial_data_structure(...)
full_output = my_function(0, lines[0], lines[1:], empty_output, **other_args)
请注意,在 Python 中,由于大多数基本数据结构的实现方式,这种编程风格不会提高您的效率,在其他面向对象代码的上下文中,它甚至可能是使事情复杂化的糟糕风格 while
解决方案。
我的建议:使用 while
循环,尽管我倾向于构建我的项目和 API,以便使用递归函数方法仍然高效且可读。我也会尽量不要在循环内产生副作用。
使用枚举索引
类似于已接受的答案……除了不使用 itertools
(恕我直言 islice
不会提高可读性),再加上 enumerate()
已经 returns 一个迭代器,所以你不需要根本不需要 iter()
:
lines = [{str(x): x} for x in range(20)] # dummy data
it = enumerate(lines)
for i, line in it:
print(line)
if i == 10: # condition using enumeration index
[next(it, None) for _ in range(5)] # skip 5
为了便于阅读,可以选择扩展最后一行:
for _ in range(5): # skip 5
next(it, None)
next()
中的 None
参数可避免在没有足够的项目可跳过时出现异常。 (对于原始问题,可以省略,如 OP 所写:"I can be sure that, if the condition is met, there are 5 or more objects left in the lines
object.")
没有使用枚举索引
如果跳过条件不是基于枚举索引,只需将列表视为 FIFO 队列并使用 pop()
:
lines = [{str(x): x} for x in range(20)] # dummy data
while lines:
line = lines.pop(0) # get first item
print(line)
if <condition>: # some other kind of condition
[lines.pop(0) for _ in range(5)] # skip 5
和以前一样,为了便于阅读,可以选择扩展最后一行:
for _ in range(5): # skip 5
lines.pop(0)
(对于大型列表,使用 collections.deque
提高性能。)