Skip to content Skip to sidebar Skip to footer

Are There A Way To Use While Loop Function As A List Tracker? And Mix With Filei/o?

to_do_list = [] while True: in_listed = input('item list:') if in_listed == 'quit': break if in_listed[0] == 'add': num1 = int(user_li[-1]

Solution 1:

Fixing your in_listed[0] == 'add' test

If you want to divide the input string into a list of words, you can use strip and split:

in_listed = input('item list: ').strip().split()

Then you can safely test for equality between in_listed[0] and "add", "rm", "quit".

Read-eval-print loop

What you are implementing is called a "shell" or a "Read-eval-print loop". I suggest simplifying the core of the loop so it reads input, identify a command, and call the appropriate command; the individual code for each command can be separated and put into functions, rather than under an immense if/elif/else forest inside the loop.

Here is what the loop might look like after simplification:

env = { 'todo_list': [], 'prompt': '$ ',  'didntQuit': True }

command_dict = {'add': cmd_add, 'rm': cmd_rm, 'print': cmd_print_todolist, 'quit': cmd_quit}

while env['didntQuit']:
    argv = input(env['prompt']).strip().split()           # read
    command = command_dict.get(argv[0], cmd_notfound)     # identify command
    ret = command(argv)                                   # execute command
    print_return_value(ret, argv)                         # error message if command failed

We have a dictionary command_dict which contains the names of all the commands. In the body of the while loop, we read input; split it into a list of words; look for the first word of the input in the command dictionary; then we evaluate the command found in the dictionary (or cmd_notfound if we didn't find a command with that name).

Then we can define the functions cmd_add, cmd_rm, cmd_print_todolist and cmd_quit outside the while loop.

Note that I moved all the global variables to a single dictionary named env (for "environment") because I am wary of global variable and I prefer to have them all in one place.

Full code

Here is the full code:

env = {
 'todo_list': [],
 'prompt': '$ ',
 'replname': 'repl-todolist',
 'didntQuit': True
 }

defcmd_add(argv):
    iflen(argv) > 2:
        date = argv[1]
        item = ' '.join(argv[2:])
    eliflen(argv) == 2:
        date = ''
        item = argv[1]
    else:
        return -1
    env['todo_list'].append((date, item))
    return0defcmd_rm(argv):
    iflen(argv) < 2:
        print('rm: please specify the index of the item you want to remove')
        return -1try:
        i = int(argv[1])
        env['todo_list'].pop(i)
        return0except ValueError:
        print('rm: failed to interpret "{}" as a list index'.format(argv[1]))
        return -1except IndexError:
        print('rm: index out of range')
        return -1defcmd_print_todolist(argv):
    print('TODO:')
    for i, (date, item) inenumerate(env['todo_list']):
        print('  ({}) {} {}'.format(i, date, item))
    return0defcmd_quit(argv):
    env['didntQuit'] = Falsereturn0defcmd_notfound(argv):
    print('{}: {}: command not found'.format(env['replname'], argv[0]))
    return -1defprint_return_value(ret, argv):
    if ret != 0:
        print('{}: command {} failed with return value {}'.format(env['replname'], argv[0], ret))

command_dict = {'add': cmd_add, 'rm': cmd_rm, 'print': cmd_print_todolist, 'quit': cmd_quit}

while env['didntQuit']:
    argv = input(env['prompt']).strip().split()           # read
    ret = command_dict.get(argv[0], cmd_notfound)(argv)   # eval
    print_return_value(ret, argv)                         # error message

File I/O

With the code structured this way, it is trivial to add new commands. Just write a new function, and add it to the dictionary of commands!

I suggest you read the tutorial on file I/O in python: Official Doc on Reading and Writing Files.

Here is an example of a "save" command which would write the todo-list to a file:

defcmd_save(argv):
  iflen(argv) < 2:
    print('save: please specify a filename to save the todo-list to')
    return -1
  filename = argv[1]
  try:
    withopen(filename, 'w') as outf:
      for i, (date, item) inenumerate(env['todo_list']):
        outf.write('TODO:\n')
          for i, (date, item) inenumerate(env['todo_list']):
            outf.write('  ({}) {} {}\n'.format(i, date, item))
     return0except:
    print('save: unable to open file "{}"'.format(argv[1]))
    return -1

Then you can add this function to the command dictionary:

command_dict = {'save': cmd_save, 'add': cmd_add, 'rm': cmd_rm, 'print': cmd_print_todolist, 'quit': cmd_quit}

Dates and sorting the todo-list

There is a python module called datetime which is really cool if you need to parse, manipulate or print dates and times. I suggest modifying the function cmd_add by replacing the line date = argv[1] with something a bit more complex:

defcmd_add(argv):
    iflen(argv) > 2:
        date = datetime.datetime.strptime(argv[1],"%m/%d").replace(datetime.datetime.today().year)
        item = ' '.join(argv[2:])
    eliflen(argv) == 2:
        date = datetime.datetime.today()
        item = argv[1]
    else:
        return -1
    env['todo_list'].append((date, item))
    env['todo_list'].sort(key=lambda item: item[0])
    return0

Here are the new features:

  • Now date is no longer a string, but instead a datetime object;
  • Since the user doesn't specify a year, I added today's year to the date (see also this answer);
  • If the user doesn't specify a date, we add the item with today's date;
  • I added .sort() at the end of the function. Now your todo-list is sorted by date!

Since the date is a datetime object, we want to modify cmd_print_todolist as well to print the time under a good format:

defcmd_print_todolist(argv):
    print('TODO:')
    for i, (date, item) inenumerate(env['todo_list']):
        print('  ({}) {} {}'.format(i, date.strftime('%m/%d'), item))
    return0

I used '%m/%d' to format the date, but you could be more fancy and add the day of the week, or write the month in words, etc. See the doc on strptime and strftime behaviour for more info on date parsing and date printing.

Post a Comment for "Are There A Way To Use While Loop Function As A List Tracker? And Mix With Filei/o?"