0

Is there a keyword that I can use to iterate a for loop without stepping the iterator? I know that it's possible to do this without such a command, by using a while loop and iterating manually, but it would greatly simplify things, in this instance, if I could just use a for loop, since continuing without iteration is the exception, not the rule. (there will significantly more conditions added to this when it is complete, all of which will require iteration). Here's my code (or, what I've written so far):

for line in file_as_list:
    response = input(line)
    if response.lower() == 'help':
        self.show_command_list()
        response = input(line)
    if response.lower() == 'loc':
        self.show_location(file_as_list, location)
        response = input(line)
    if response.lower() == 'exit':
        save_changes = input('Would you like to save the changes you have made? (Y/N) ')
        while (save_changes.upper() != 'Y') & (save_changes.upper() != 'N'):
            save_changes = input('That is not a valid response. Try again. ')
        if save_changes.upper() == 'N':
            temp = file_as_list
            print('Changes were not saved.')
        else:
            for line in file_as_list[location:]:
                temp.append(line)
            print('Changes were saved.')
        break
    if response.lower() == 'inline':
        line += ' //' + input(line + ' //')
        print('Line generated: ' + line)
    location += 1
    temp.append(line)
3
  • 1
    that sounds like you want a while loop in a for loop Commented Sep 18, 2018 at 22:53
  • 1
    To the best of my knowledge, there isn't a good way to do this without using a while loop and iterating manually. However, why not just put the iteration at the very end of the loop, and make each "failure" just call continue? Commented Sep 18, 2018 at 22:56
  • This would be a great place to start using functions. Commented Sep 18, 2018 at 23:07

3 Answers 3

2

I think you want two nested loops. Try something like this:

for line in file_as_list:   # outer loop
    while True:             # inner loop
        response = input(line).lower()
        if response == 'help':        # these two options don't exit the inner loop
            ...
        elif response == 'loc':       # so they won't consume a line from the for loop
            ...
        else:
            break

    if response == 'exit':            # these other two conditions are outside the while loop
        ...
    elif response == 'inline':        # so a new line will be fetched after they run
        ...

If either of the first two conditions are met, the inner loop will keep on running without changing line. Only if the break gets hit will the inner loop end, and the other conditions get tested. After they do their thing, a new value will be assigned to line, as the for loop continues iterating.

Unrelated to your main question, I also changed the input line to call lower on the input immediately before saving it to response. That means the conditions don't need to keep calling it repeatedly. Your code isn't wrong there, but if you never care about the user's capitalization, throwing it away right off the bat can simplify things.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use an explicit iterator like

it = iter(file_as_list)
for line in it:
    input(line)
   ... 
    input(next(it))

and so on. Just be sure to properly handle the case where you run out of lines!

2 Comments

Also check out the enumerate() built-in.
I think you want input(next(it)) on that last line of your code. But I think this is answering the opposite problem than what the questioner wants. They don't need to take extra values, but instead want something like a continue statement that doesn't get a new value from the for loop, it just keeps on using the current one.
0

You have two types of commands: ones that advance the iterator, and ones that don't. You could also call it action vs descriptive commands. Your best bet conceptually is to have a while loop that will continue to seek input until you get an action command. This while loop will live inside the existing for loop.

The advantage of this is that currently, your descriptive commands like "help" and "loc" can't be repeated, but you probably want them to be.

Another decision I would recommend is to use distinct functions to implement each command. By giving the commands a consistent interface, you make the code easier to maintain and understand. By registering the commands in a dictionary, you can make your lookup faster and more flexible.

The following concept has a bunch of functions that return a tri-state boolean value and an update. The boolean is True if the command wants to stay on the current line, False to continue. None to exit. The line update is usually just the input.

# in __init__
...
   self.command_map = {
        'help': self.help,
        'loc': , self.loc,
        'exit': self.exit,
        'inline': self.inline,
    }
    self.temp = []
...

def help(self, file_as_list, location, line):
    self.show_command_list()
    return True, line

def loc(self, file_as_list, location, line):
    self.show_location(file_as_list, location)
    return True, line

def exit(self, file_as_list, location, line):
    save_changes = ''
    while len(save_changes) != 1 or save_changes.upper() not in 'YN':
        save_changes = input('Would you like to save the changes you have made? (Y/N) ')
    if save_changes.upper() == 'N':
        self.temp = file_as_list
        print('Changes were not saved.')
    else:
        self.temp.extend(file_as_list[location:])
        print('Changes were saved.')
    return None, line

def inline(self, file_as_list, location, line):
    line += ' //' + input(line + ' //')
    print('Line generated: ' + line)
    return True, line

def process(self):
    for location, line in enumerate(file_as_list):
        stay = True
        while stay:
            response = input(line)
            command = command_map.get(response.casefold())
            if command is None:
                print(f'Command "{response}" not found. Try again')
            else:
                stay, line = command(file_as_list, location, line)

        if stay is None:
            break
        self.temp.append(line)

Given command_map, you can do lots of things easier: for example, you can reimplement show_command_list to do something with sorted(command_map.keys()). I'm sure you can see how relatively easy it is to add commands to your list. You don't have to repeat boilerplate code, just be careful with the inputs and return values.

This construction is also much easier to iterate manually if you don't like the idea of having nested loops:

def process(self):
    stay = False
    iterator = enumerate(file_as_list)
    while True:
        if not stay:
            try:
                location, line = next(iterator)
            except StopIteration:
                break
        response = input(line)
        command = command_map.get(response.casefold())
        if command is None:
            print(f'Command "{response}" not found. Try again')
            stay = True
        else:
            stay, line = command(file_as_list, location, line)

        if stay is None:
            break
        if not stay:
            self.temp.append(line)

As you can see, this method requires quite a bit more special handling for the various conditions.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.