Lucas123
Lucas123

Reputation: 61

How to return the iterator to the previous line in Python

I am processing 2 lines at a time. To do this I have a for loop using the enumerate:

for id, line in enumerate(file):
    if id % 2 == 0:
        line1 = line
        print("First line: ", line1)
    else:
        line2 = line
        print("Second line: ", line2)
        print("Both lines: ", line1 + line2)

Everything is working perfectly for this input:

This is line 1
This is line 2

and the output is:

First line: This is line 1
Second line: This is line 2
Both lines: This is line1 This is line2

Problem: i do not want to process lines start with '_:'. How can I do that? I can simply add a condition such as if line.startswith('_:') but now the iterator will be incremented anyway so if I have an input like this:

Line1
_:Anthing
Line2

:_Anything will be considered line 2, just by checking if it starts with '_:', but since it starts with '_:', I do not want to process it, I still want my second line to be Line2. So after checking the line, if it starts with a special character, how can I return the iterator back to the last line without special characters?

I this case I want the output to be:

First Line: Line1
_:Anything
Second Line: Line2
Both lines: Line1 Line2

Upvotes: 0

Views: 785

Answers (2)

chepner
chepner

Reputation: 531225

It appears that you want to see each line of the file, but whether a line is even or odd depends as much on its value as its position in the file. We only want to make such an assignment after we check its prefix, perhaps with something like

parity = itertools.cycle([True, False])  # even, odd, even, odd, ...
for line in file:
    if line.startswith("_:"):
        print(line)
        continue
    if next(parity):
        line1 = line
        print("First line: {}".format(line1))
    else:
        line2 = line
        print("Second line: {}".format(line2))
        print("Both line: {}{}".format(line1, line2))

The infinite, alternating Boolean series parity replaces the line number you get from enumerate. It lets you wait until after you decide to use line to "ask" whether this is an even or odd line.


Another way to look at this is that your original code iterates over parity and file simultaneously, rather than advancing parity separately. You could rewrite your original code as

for is_even, line in zip(cycle([True, False], file):
    if is_even:
        line1 = line
        print("First line: ", line1)
    else:
        line2 = line
        print("Second line: ", line2)
        print("Both lines: ", line1 + line2)

and so see that my contribution is simply to replace the implicit call to next(parity) with an explicit, conditional call.

Upvotes: 3

Patrick Artner
Patrick Artner

Reputation: 51653

You do not have "iterators" - you memorize single lines:

t = """Line1
_:Anthing1
Line2 
Line3
_:Anthing2
Line4"""

line1 = None   # these are not iterators, they are just lines
line2 = None   # same here, just one memorized line

# the index you get is not needed at all ...
for line in t.split("\n"):  # instead of "for line in file:"
    # base case
    if line.startswith("_:"):
        print(line) # no processing

    elif line1 is None and line2 is None:  # remember first line
        line1 = line
        print("First line: ", line1)

    elif line1 is not None: # we got a first line, so this is the second one
        line2 = line
        print("Second line: ", line2)
        print("Both lines: ", line1 + line2)

        # do processing on line1 and line2

        # reset memorized lines
        line1 = None
        line2 = None

Output:

First line:  Line1
_:Anthing1
Second line:  Line2 
Both lines:  Line1Line2 
First line:  Line3
_:Anthing2
Second line:  Line4
Both lines:  Line3Line4

Upvotes: 1

Related Questions