Monday, April 8, 2024

 

2D Dictionaries


Remember that dictionaries are very similar to lists, except that they store data as key:value pairs. The value is what it's worth and the key is what it is called. The key is used to access the value, and keys are more meaningful than index numbers.



Dynamically Adding To A 2D Dictionary

This code dynamically adds to a 2D dictionary by starting with an empty dictionary and using an infinite loop to add user input.

clue = {}

while True:
  name = input("Name: ")
  location = input("Location: ")
  weapon = input("Weapon: ")

  clue[name] = {"location": location, "weapon":weapon} #line 7

  print(clue)

output 
Name: angshu
Location: burdwan
Weapon: hammer
{'angshu': {'location': 'burdwan', 'weapon': 'hammer'}}


The real magic happens on the 7th line of code. Instead of using .append() like we would with a list, we create a new dictionary entry.

The key is the name of the beast, but the value is a whole new dictionary that contains the details of the beast.

Each key:value pair in the dictionary is now a key that accesses a related dictionary

Pretty Printing
This example shows you how to add a prettyPrint() subroutine that works with a 2D dictionary.

clue = {}
def prettyPrint():
  print()
  
  for key, value in clue.items(): #This iterates over each key-value pair in the clue dictionary. Inside the loop
    # moves along every 'key:subDictionary' pair and outputs the key (the name of the character).
    print(key, end=": ")
    for subKey, subValue in value.items(): #This nested loop iterates over each key-value pair in the nested dictionary associated with the current key
      # (nested) `for` loop moves along every subkey and subvalue in each subDictionary.
      print(subKey, subValue, end=" | ")
    print()
    
while True:
  name = input("Name: ")
  location = input("Location: ")
  weapon = input("Weapon: ")

  clue[name] = {"location": location, "weapon":weapon} 

  prettyPrint()


Accessing a Single Item

To access a single item in a 2D dictionary, we use two square brackets just like with a 2D list.

john = {"daysCompleted": 46, "streak": 22}
janet = {"daysCompleted": 21, "streak": 21}
erica = {"daysCompleted": 75, "streak": 6}

courseProgress = {"John":john, "Janet":janet, "Erica":erica}

print(courseProgress)

print(courseProgress["Erica"])
# The bracket contains the key that references the sub dictionary.To access one item, I use two square brackets []. So to see only Erica's results, I would add this
print(courseProgress["Erica"]["daysCompleted"]): #if we only want to see how many days Erica has completed

Wednesday, April 3, 2024

2D Dynamic Lists

 

2D Dynamic Lists
Dynamic lists are lists that we populate as we go, getting user input and adding it to the list as we go.
We're combining several techniques here. I've left detailed code comments to help. Remember, comments can be found with # comment in green inside the code.

Loops, append() and break

Here's an example to get some simple user details(name, age, computer preference) and add it to a list as a full row. This list will keep taking input until the user answers 'y' to the 'exit?' question.

Once we collect the user's input in a row, we will append the entire row to the list. The columns are maintained, and we are keeping the structure of 2D lists.


Lets try this coding :

listOfShame = [] 
# Creates an empty list.

while True: 
  # Starts a never ending loop (until we end it)
  name = input("What is your name? ")
  age = input("What is your age? ")
  pref = input("What is your computer platform? ")
  # Get the user input.

  row = [name, age, pref] 
  # Assigns the 3 variables into a single row.

  listOfShame.append(row) 
  # Adds the contents of the row variable at the end of the list

  exit = input("Exit? y/n") 
  # Get user choice to quit, yes or no?

  if (exit.strip().lower()[0] == "y"): 
    # strip removes unwanted spaces from the input. lower()[0] makes sure the first character of the input is lower case so it can be compared to 'y'
    break # break ends a loop and jumps to the next line of code that is not part of the loop.
    
print(listOfShame) # Outputs the list. Note this is NOT part of the loop (not indented), it only runs once the loop ends.



Pretty Printing



Man, that print(listOfShame) output sure is ug-leeee.
In the code below, I've added a prettyPrint subroutine to beautify the output. 

def prettyPrint():
  print() 
  # Puts a blank row at the top
  for row in listOfShame: 
    #loops to the next row when the end of the current one is reached
     print(row) 
    # prints the new row
  print() 
  # prints a blank line between rows
    

listOfShame = [] 

while True: 
  name = input("What is your name? ")
  age = input("What is your age? ")
  pref = input("What is your computer platform? ")
  
  row = [name, age, pref] 

  listOfShame.append(row) 

  exit = input("Exit? y/n") 

  if (exit.strip().lower()[0] == "y"):
    break 

prettyPrint() 
# Call the prettyPrint subroutine instead of printing the list directly.


There is a bit of weirdness. The rows are printing out, but they just look like a list with all those symbols. We need one loop to extract each row and one loop to extract each item from the columns.


Prettier Printing?

This version of prettyPrint() uses fStrings to further line up the tabs.
Note: this only shows the updated subroutine.

def prettyPrint():
  print() 
  for row in listOfShame: 
    for item in row: 
      # item refers to each item in the column for that row
     print(f"{item:^10}", end=" | ") 
    

listOfShame = [] 

while True: 
  name = input("What is your name? ")
  age = input("What is your age? ")
  pref = input("What is your computer platform? ")
  
  row = [name, age, pref] 

  listOfShame.append(row) 

  exit = input("Exit? y/n") 

  if (exit.strip().lower()[0] == "y"):
    break 

prettyPrint() 
# Call the prettyPrint subroutine instead of printing the list directly.


Add or Remove?

We can add records, but let's expand to give the user the choice of whether to add or remove. Do we want to remove the entire row or just one item?

We ask the user to choose between adding and removing. If they choose remove, we 
-ask for a name on the list (make sure it is spelled correctly)
-extract each row, one at a time, from the list
-check the row to see if it contains the name
-if the name is in the row, use the .remove() method to remove the whole row, not just the name.

def prettyPrint():
  print() 
  for row in listOfShame: 
    for item in row: 
      # item refers to each item in the column for that row
     print(f"{item:^10}", end=" | ") 
listOfShame = [] 

while True: 
  menu = input("Add or Remove?") # Gives the user a choice prompt and stores their input.

  if(menu.strip().lower()[0]=="a"): # Uses selection to run the 'add' code if user inputs 'a'. I've "sanitized" the input here too.[0]: This indexing operation accesses the first character of the modified string obtained after stripping whitespace and converting to lowercase. Indexing in Python starts from 0, so [0] accesses the first character of the string.
    
    name = input("What is your name? ")
    age = input("What is your age? ")
    pref = input("What is your computer platform? ")
    
    row = [name, age, pref] 
  
    listOfShame.append(row) 
    # All the 'add' code is now indented, so it's part of the 'add' branch and will only run if the user enters 'a'.

  else: # If the user doesn't choose 'a', run this new remove code instead.
    name = input("What is the name of the record to delete?") # Get the input of a name
    for row in listOfShame: # Use a loop to extract one row at a time
      
      if name in row: # Check if the name is in the extracted row.
        listOfShame.remove(row) # remove the whole row if name is in it

  prettyPrint()



Coding Challenge

1. Have a menu that asks if you want to add, view, move or edit a 'to do'.


2.If you choose 'add' then the system should:Prompt you to input what the to do is, when it is due by and the priority (high, medium or low).
Add the 'to do' to the list.


3. 'View' should give two options:View all - shows all 'to dos' with a pretty print.
View priority - allows you to search for high, medium or low priority and only see matching tasks.


4.'Edit' allows you to change any of the information within one of the 'to dos'.

5. 'Remove' lets you completely remove a 'to do' when it is 'to done'.

STEP-1

# Function to add a to do
def add_todo():
task = input("Enter the task: ")
due_date = input("Enter the due date: ")
priority = input("Enter the priority (high, medium, low): ")
todo_list.append({'Task': task, 'Due Date': due_date, 'Priority': priority})
print("Task added successfully.")


# Function to view all todos
def view_all():
print("All To Dos:")

print(f"{index}. Task: {todo['Task']}, Due Date: {todo['Due Date']}, Priority: {todo['Priority']}")


# Function to view todos by priority
def view_priority(priority):
print(f"To Dos with priority {priority}:")
for index, todo in enumerate(todo_list, start=1):
if todo['Priority'].lower() == priority.lower():
print(f"{index}. Task: {todo['Task']}, Due Date: {todo['Due Date']}, Priority: {todo['Priority']}")


# Function to edit a todo
def edit_todo():
view_all()
index = int(input("Enter the index of the task you want to edit: ")) - 1
if 0 <= index < len(todo_list):
task = input("Enter the new task: ")
due_date = input("Enter the new due date: ")
priority = input("Enter the new priority (high, medium, low): ")
todo_list[index] = {'Task': task, 'Due Date': due_date, 'Priority': priority}
print("Task edited successfully.")
else:
print("Invalid index.")


# Function to remove a todo
def remove_todo():
view_all()
index = int(input("Enter the index of the task you want to remove: ")) - 1
if 0 <= index < len(todo_list):
del todo_list[index]
print("Task removed successfully.")
else:
print("Invalid index.")


# Main program
todo_list = []


while True:
print("\nMenu:")
print("1. Add a To Do")
print("2. View To Dos")
print("3. Edit a To Do")
print("4. Remove a To Do")
print("5. Exit")


choice = input("Enter your choice: ")


if choice == '1':
add_todo()
elif choice == '2':
print("\nView Options:")
print("1. View All")
print("2. View by Priority")
view_choice = input("Enter your choice: ")
if view_choice == '1':
view_all()
elif view_choice == '2':
priority = input("Enter the priority (high, medium, low): ")
view_priority(priority)
else:
print("Invalid choice.")
elif choice == '3':
edit_todo()
elif choice == '4':
remove_todo()
elif choice == '5':
print("Exiting program.")
break
else:
print("Invalid choice. Please enter a number from 1 to 5.")

STEP-2

# | Name | Date | Priority
import os, time
todo = []

def add():
  time.sleep(1)
  os.system("clear")
  name = input("Name > ")
  date = input("Due Date > ")
  priority = input("Priority > ").capitalize()
  row = [name, date, priority]
  todo.append(row)
  print("Added")

def view():
  time.sleep(1)
  os.system("clear")
  options = input("1: All\n2: By Priority\n> ")
  if options=="1":
    for row in todo:
      for item in row:
        print(item, end=" | ")
      print()
    print()
  else:
    priority = input("What priority? > ").capitalize()
    for row in todo:
      if priority in row:
        for item in row:
          print(item, end=" | ")
        print()
    print()
  time.sleep(1)

def edit():
  time.sleep(1)
  os.system("clear")
  find = input("Name of todo to edit > ")
  found = False
  for row in todo:
    if find in row:
      found = True
  if not found:
    print("Couldn't find that")
    return
  for row in todo:
    if find in row:
      todo.remove(row)
  name = input("Name > ")
  date = input("Due Date > ")
  priority = input("Priority > ").capitalize()
  row = [name, date, priority]
  todo.append(row)
  print("Added")

def remove():
  time.sleep(1)
  os.system("clear")
  find = input("Name of todo to remove > ")
  for row in todo:
    if find in row:
      todo.remove(row)

while True:
  menu = input("1: Add\n2: View\n3: Edit\n4: Remove\n> ")
  if menu == "1":
    add()
  elif menu == "2":
    view()
  elif menu == "3":
    edit()
  else:
    remove()

  time.sleep(1)
  os.system("clear")

Tuesday, April 2, 2024

Two-Dimensional List

 Two-Dimensional List

Pay close attention, folks, because 2D lists are basically tables.
Tables are two-dimensional data structures where we can store data both vertically and horizontally.
Usually this means that vertical data is used for fields (one category - name, ID, favorite biscuit, etc.) and horizontal data is used for records (all the data for each category).
Behind the scenes, we see a list inside a list. Forget what you know about reading a table with math or geography: 'across the corridor (x-axis) first and then down the stairs (y-axis)'.

Here, we will do row index first and then the column index.

Remember...
Here's a 1D list. We have the list name as a variable, single equals to set the value, and sqaure brackets to show this is a list. 2D lists are very similar.

my1DList = ["Johnny", 21, "Mac"]

Adding The Second Dimension

To add the second dimension, we put lists inside the first list.

Each new list has its own set of square brackets and is separated by a comma. This layout of code is nice to help us visualise the 2D list as a table, but...

my2DList = [ ["Johnny", 21, "Mac"],
                       ["Sian", 19, "PC"],
                       ["Gethin", 17, "PC"] ]

...you can also lay it out like this below:

my2DList = [ ["Johnny", 21, "Mac"], ["Sian", 19, "PC"], ["Gethin", 17, "PC"] ]

Now, let's print this list.

Printing From a 2D List

Remember, any comments about the code are written in green like this:

the entire list

We can print an entire 2D list just like we do with a 1D list. However, this will output (print) all of the square brackets, commas, etc.

print(my2DList)

a single row
To print a single row, use a single square bracket [] in the print command. However, you will still get all of those square brackets and commas.

In this example, I'm outputting the first row (index 0) - all of the data about Johnny.

print(my2DList[0])

a single piece of data
The first square bracket references the list, while the second references the item inside that list.
Here are a couple of examples:

my2DList = [ ["Johnny", 21, "Mac"],
             ["Sian", 19, "PC"],
             ["Gethin", 17, "PC"] ]

print(my2DList[0][0])
# This code outputs 'Johnny'. It's Johnny's name from list 0 (first square bracket), item 0 (second square bracket)

print(my2DList[1][2])
# This code outputs 'PC'. It's Sian's computing preferene from list 1 (first square bracket), item 2 (second square bracket)

Editing a 2D List
We can edit values in a 2D list in the same way as variables and 1D lists. You just need to change the value to the new row and column index numbers.
In this example, Sian has joined the dark side, so we're updating her computing preference to Linux.

my2DList = [ ["Johnny", 21, "Mac"],
             ["Sian", 19, "PC"],
             ["Gethin", 17, "PC"] ]

my2DList[1][2] = "Linux"
# The line above changes list 1, item 2 from PC to Linux

print(my2DList[1])
# I'm using this line to output list 1 to check that the change has happened correctly.

Coding Challenge


Randomly generate a series of number between 0 and 90.
Allocate each number to a place in a 2D list.
The numbers should be in numerical order, left to right.
Numbers should not be repeated.
The center square should not contain a number. It should contain the word 'BINGO!'.


import random

bingo = []

def ran():
  number = random.randint(1,90)
  return number

def prettyPrint():
  for row in bingo:
    print(row)

numbers = []
for i in range(8):
  numbers.append(ran())

numbers.sort()

bingo = [ [ numbers[0], numbers[1], numbers[2]],
          [ numbers[3], "BINGO", numbers[4] ],
          [ numbers [5], numbers[6], numbers[7]]
        ]

prettyPrint()

  2D Dictionaries Remember that dictionaries are very similar to lists, except that they store data as key:value pairs. The value is what it...