跳过枚举列表对象(python)中的迭代

时间:2015-01-25 16:05:44

标签: python loops skip

我有代码

for iline, line in enumerate(lines):
    ...
    if <condition>:
        <skip 5 iterations>

我想,如你所知,如果满足条件,则for循环跳过5次迭代。我可以肯定的是,如果条件满足,“行”对象中还有5个或更多的对象。

存在一系列字典,必须按顺序循环

6 个答案:

答案 0 :(得分:8)

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

这实际上取决于你在迭代什么以及你想做什么。

将自己的代码与iterislice一起使用:

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)

答案 1 :(得分:6)

执行此操作的标准习惯用法是创建迭代器,然后使用其中一种消费者模式(请参阅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

答案 2 :(得分:0)

正如Padraic Cunningham所述,您可以使用while循环执行此操作,也可以使用字典替换if语句:

iline = 0
skip = {True:5, False:1}

while iline > len(lines):
    line = lines[iline]
    ...
    iline += skip[condition]

答案 3 :(得分:0)

使用外部标志并在满足条件时进行设置,并在循环开始时进行检查:

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。

答案 4 :(得分:0)

您可以使用带递归的函数式编程样式,首先将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)

可选地,如果它不需要返回任何内容,您可以将这些代码行调整为函数调用,返回结果将为None

然后你实际上称它为某个地方:

other_args = get_other_args(...)

my_function(0, lines[0], lines[1:], **other_args)

如果你需要函数为每个索引返回不同的东西,那么我建议稍微修改它以考虑你想要的输出数据结构。在这种情况下,您可能希望将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,以便使用递归函数方法仍然是高效和可读的。我也会尽量不允许循环内的副作用。

答案 5 :(得分:0)

使用枚举索引

类似于已接受的答案……除了不使用itertools(恕我直言islice不会提高可读性),加上enumerate()已经返回了迭代器,因此您不需要{{ 1}}:

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) 中的None参数可以避免出现异常。 (对于原始问题,可以省略,因为OP写道:“我可以确定,如果满足条件,则next()对象中将剩下5个或更多对象。”)

不使用枚举索引

如果跳过条件不是基于枚举索引,则只需将列表视为FIFO队列,然后使用lines从列表中使用:

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) 来提高性能。)