Charming Python with Lists

vickilanger

Vicki Langer

Posted on January 6, 2022

Charming Python with Lists

If learning to code with foo, bar, and math examples are your kryptonite, keep reading. This series uses relatable examples like flipping coins, books, bread, and groceries.

Don't forget, while writing your code, there are lots of tools there to help you.


Jump To:

What are Data Structures

Data structures are collections or groups of data. Typically, data structures hold data types and other data structures. Think of data structures as boxes that have certain rules for what can go in them. You can fit other boxes inside this box as well as other things too.

Python has two types of data structures. There are primitives, which you already learned about, and there are collections. Data types, or primitives, include the basic structures we talked about earlier: integers, floats, strings, and boolean. Primitives also include a type called complex. We haven’t and won’t go over these as they are used in very few things (eg electrical engineering, physics, etc). Oftentimes, we will want to group primitives together. We do this using collections.

Collections allow us to group objects with similarities together. A collection can hold as many objects as you want. Objects can be primitives or collections. Yes, we can put collections inside of other collections. Then we can even put that collection of collections in another collection. I’m sure that was super confusing, but don’t worry. We will go over this in detail later in the section about nesting.

For now, let’s stick to talking about what the built-in data structures are. In Python, we have lists, dictionaries, sets, and tuples. You can build, or implement, data structures of your own (eg stack, queue, tree, etc), but we really should continue learning the fundamentals first. First up, shall we talk about lists?

Lists

Lists are exactly what they sound like. They help you group similar things or objects together. Typically these things have something in common. You’ve used them in real life whether you realize it or not. Lists also have the benefit of being ordered or numbered. We’ll talk about this soon.

Real-life examples

Snoopy from The Peanuts shuffling cards and looking sude to side skeptically

Keeping track of scores in a card game

You likely start with a blank piece of paper. Even though it’s empty, we could call it a list because we know you’re about to write down scores for the game. Each time someone gains points, you add them to the end of the list. Tada! You have a list with values on it.

Have you ever made and used a grocery list?

You likely start with a blank piece of paper. Even though it’s empty, we could call it a list because we know you’re about to write down items we need to get at the store. Every time you think of something you need at the store, you add it to your list. Tada! You have a list with values on it.

Now for the important part of that grocery list. You’re at the store. Every time you find an item and put it in your basket, you can remove the item from your list. Hopefully, by the time you’re done, the list will be empty.

Syntax

Lists can have any number of items or even zero items. You’ll find that since a list is often expected to have multiple items, its name will typically be plural. Many times, you’ll see each item and its comma on a separate line. For space reasons, most of our example lists will be on one line.

# make an empty list
pets_list = []

# list with items
my_scores_list = [12, 23, 7, 5, 54]
your_scores_list = [9, 21, 14, 35]
Enter fullscreen mode Exit fullscreen mode

screenshot of python tutor showing the above code with each integer in each list labelled 0-4, starting at 0
Lists can contain any mix of data structures, variables, and hard-coded data. This means we can have lists inside of lists, but again, we'll go over that shortly in the section about nesting. For now, know that we can include any mix of variables and hard-coded data in a list.

flipper = "spatula"
chopper = "knife"
scooper = "spoon"
stabber = "fork"

cooking_equipment_list = [flipper, chopper, scooper, stabber, "bowl"]
Enter fullscreen mode Exit fullscreen mode

screenshot of python tutor showing the above code with each object in the list labelled 0-4, starting at 0
Make note that even though you gave the list the variables, the list used the variables to find the actual value of each variable.

Did you notice anything weird about how the list items show up in Python Tutor or the screenshots? The items are numbered, but what number was given to the first item in the list?

Relearn How To Count with Zero-Based Numbering

graphic showing a list of tools. first tool is labelled 0, second tool is labelled 1, third tool is labelled 2, and 4th tool is labelled 3
Typically, when we learn to count we start from 1, right? In Python, and most other programming languages, we start counting from zero. We call this zero-based numbering. This means the first thing in your list will always be at the position, or index, zero.

graphic showing a list of tools. first tool is labelled 0 and -4, second tool is labelled 1 and -3, third tool is labelled 2 and -2, and 4th tool is labelled 3 and -1

By the way, we can also index backwards, using negative numbers. This would make the last item in your list index position -1 and the second to last item in your list index position -2. This can help when you are trying to get an item from the end of your list.

Finding your Maximum Index

This also means your last index position will always be one less than the length of your list. Do you know why? Look at the cooking_equipment_list above. It is 5 items long and its last or biggest index is 4. You’ll find it is common to save len(list) - 1 into a variable called max_index or last_index. This will become helpful soon when we learn how to get items from a list. This could look like last_index = len(box_contents_list) - 1 and it could be read as “the last index is the length of the box_contents_list minus one”.

Of course, if you know how long the list is, you could hard-code the length. This will work at first, but what if you add to the list later? If you hard-code it, you would have to go back and fix this part too. This could become painful, especially with longer lists where we don’t know the length or if other people are adding to the list and didn’t know something else needed to be changed too.

What can we do with lists?

Getting an Index

What is this “getting” you speak of? A lot of programming is based on the computer’s ability to get things and set things. Getting means that you have asked for the item and setting means you have changed an item. Let’s use hobbies as an example. Just like when we made a list, when we want to get or set indices, we use [].

# Ceora has some hobbies
music = "K-pop"
curiosity = "asking awesome questions"
ceora_hobbies_list = [music, curiosity, "memes", "advocacy", "DX", "Hamilton"]

# get hobby from index 2
print("hobby at index 2:", ceora_hobbies_list[2])

# set/change/update then print hobby at index 2
ceora_hobbies_list[2] = "Philly"
print("changed hobby at index 2:", ceora_hobbies_list[2])

# get hobby from second to last index
print("2nd from last index:", ceora_hobbies_list[-2])
Enter fullscreen mode Exit fullscreen mode

Did you notice we used the same index for the first two sections after creating the list? This is on purpose. In the first section, we want to “get the current hobby at index 2 and print it”. In the next part, we want to “set or change the hobby at index 2 and print it” to verify that it changed. The last bit is just showing how we can use negative indices.

You could also choose to get the index and save it into a variable like this code below.

# get hobby from index 2
hobby_3 = ceora_hobbies_list[2]
print("hobby at index 2:", hobby_3)
Enter fullscreen mode Exit fullscreen mode

If you haven’t already, go ahead and give this indexing a try before moving forward.

Slicing

If you ever wanted a certain portion of a list, you can get it by cutting from one position to another. We call this slicing. Let’s say we have a loaf of bread and we want all the slices, except the pieces on either end. You might initially think we need to know how many slices there are, but we don’t.

2 loaves of different kinds of bread with some slices cut and a knife

To get the parts of the loaf we want, we can use slicing. Slicing also uses [] but it requires more info. When slicing, you’ll use square brackets with two numbers in between. The two numbers will be separated by a colon :. It should look like this [2:7]. This would mean you want everything from index 2 up to but not including index 7.

From what we know so far, there are multiple ways we could get all slices of bread without the end pieces. We will need to combine slicing with either negative indexing or the max index that we talked about earlier. Let’s see how this can be done both ways. I think it’s time to make a sandwich, what do you think?

# get sandwich bread 2 different ways
bread_loaf_list = ["end piece", "slice", "slice", "slice", "other end piece"]

# use slicing with negative indexing
bread_loaf_without_ends = bread_loaf_list[1:-1]
print("sandwich bread retrieved with negative indexing:", bread_loaf_without_ends)

# use slicing with max index
last_index = len(bread_loaf_list) - 1
different_loaf_without_ends = bread_loaf_list[1:last_index]
print("sandwich bread retrieved with max index:", different_loaf_without_ends)
Enter fullscreen mode Exit fullscreen mode

Notice, -1 and the last_index variable refer to the same index position and they are not included in the sliced section you asked for.

We used two different ways to get the same result. Remember, there are often different ways things can be done with code. This means there is no one right way to do things, but there are some guidelines on why we would choose one way over another. There are two main goals when deciding which way to code something. Generally, we prioritize readability or how easy this code is to read without assistance. The other goal is performance or how quickly the computer can read and process the code. This is important, but not near as important as being able to understand the code. When you’re learning, prioritize readability and you can learn about performance later. For readability, you could also have chosen to use loops to iterate through the list.

Iterating

car continuously driving around a loop de loop rollercoaster style
If you don’t recall what a loop is, you can always go back to refresh your memory Or, take a look at this example and see if it’s enough to conjure up the memory. Remember, “iterating” and “running a loop” are used interchangeably where one iteration is one use of the loop.

bread_loaf_list = ["end piece", "slice", "slice", "slice", "other end piece"]

# get sandwich bread a 3rd way, with a loop
for slice in bread_loaf_list:
    if slice == "slice":
        print(slice, end=", ")
Enter fullscreen mode Exit fullscreen mode

If you run this example, clicking the “next” button in Python Tutor will show you what happens at each step.

Here we have a list, the same one we used before. Then we are using a loop to say “I want to look at the first piece of the loaf to check if it is a slice. If it is a slice, it will get printed with a comma and a space , after it.” That would be one iteration. After our first iteration, we’ve checked the first piece of bread. The loop then moves to the next piece and does the same thing as it did the first time. Then it repeats until it gets to the last item in the list.

Printing is fun and all, but let’s see what else we can do with lists.

Some Methods You Can Use with Lists

We have a bunch of list methods.

  • append(item) - adds an item to the end of a given list
  • insert(index, item) - adds a given item at a given position
  • pop(index) - remove and return the item at the given position in the list
  • count(item) - return the number of times a given item is in the list
  • reverse() - reverse order of the list
  • clear() - remove all items from the list


Unlike string methods that give you a new string, list methods actually change the list you’re working with. This happens because lists are mutable and strings are immutable. Mutable means that it can change or mutate. Immutable means it cannot change or it cannot mutate. Lists being mutable or changeable is incredibly helpful. Think about your real-life lists. We’re constantly adding to them, removing things, counting the items, and so much more. Python allows us to do all of these things.

Lots and lots of different people of different ages, colors, and abilities reading books

In real life, a chalkboard or notebook would be mutable and art in a museum would be considered immutable. A published book could also be considered immutable, but plans for reading a book may be changed based on different things.

Here is a list example with some examples of methods. Try running the making of the list and start by running each method separately to see what happens. If you run all methods at once, the final output will include all of the methods performed in the order they were given. Once you’ve run each one individually, try figuring out what the end result should be. Then go ahead and add them together and see what the end result is.

prologue_str = "Once upon a time, I yelled at an alpaca while riding a motorcycle."
chapter_1_str = "I jumped on a birdbath in a library because a zebra told me to."
chapter_2_str = "Then, I kicked a pickle on a table because I found 1,000 gold bars"
chapter_3_str = "I sang to a spoon in line at the bank because I can't control myself!"
cat_picture_str = "cat"

planned_reading_list = [prologue_str, chapter_1_str, chapter_2_str]

# you have extra time, let's read chapter 3 too
planned_reading_list.append(chapter_3_str)

# never mind, you don't have time for the list chapter
planned_reading_list.pop(-1)

# oh wait, there was a picture after chapter 1
planned_reading_list.insert(1, cat_picture_str)

# want to see how goofy the book is backward?
planned_reading_list.reverse()

# anyway, how many items are "cat"?
cat_count = planned_reading_list.count("cat")
print(cat_count)

# done reading? Clear your reading to-do list
planned_reading_list.clear()
Enter fullscreen mode Exit fullscreen mode


​​

By the way, if you had even more reading to do, you can also add multiple lists together. Try making some lists and adding them together. When you add them together, they will be in the order you typed them. In the example below, not_mammals_list will be first, then mammals_list.

mammals_list = ["cat", "dog"]
not_mammals_list = ["snake", "cat", "fish"]

animals = not_mammals_list + mammals_list
Enter fullscreen mode Exit fullscreen mode

Nesting Lists

Remember earlier when I mentioned lists could be inside lists? We call these nested lists or a list of lists. Why would we even need that? Let’s talk about a couple of examples.

a picture of a door separates into a kitchen and a laundry room. the laundry room separates into different items from the laundry room. from the laundry room, we have a basket with lots of dirty clothes in it
Think of a home as a list of lists. How could you categorize a home? Rooms could be lists inside the home. Then things inside the room could be items in the room’s list. If one of the rooms has a cabinet, that would be another list, and items inside the cabinet could be items in the cabinet list.

You could also look at a book as a nested list. You can run this code or make something similar that makes sense to you. In Python Tutor, it will draw arrows to show you where each of the lists is being used. You can hover your mouse over the arrows to highlight them. If it’s getting confusing, Try commenting out a chapter or two. Once you understand what is happening you can add them back in one at a time.

# some sentences
sentence_1_list = ["I", "jumped", "on", "a", "birdbath", "in", "a", "library", "because", "a", "bird", "told", "me", "to."]
sentence_2_list = ["I", "karate", "chopped", "a", "pickle", "at", "the", "dinner", "table", "because", "someone", "offered", "me", "1,000,000", "gold", "bars"]
sentence_3_list = ["I", "sang", "to", "a", "spoon", "in", "line", "at", "the", "bank", "because", "I", "can't", "control", "myself!"]
sentence_4_list = ["I", "yelled", "at", "an", "alpaca", "while", "riding", "a", "motorcycle", "because", "I", "like", "getting", "wet."]
sentence_5_list = ["The", "glamorous", "alien", "squashed", "an", "angry", "ant",]
sentence_6_list = ["The", "scrawny", "elephant", "squeezed", "a", "slimy", "doctor",]

# some chapters that contain sentences
chapter_1_list = [sentence_1_list, sentence_2_list]
chapter_2_list = [sentence_3_list, sentence_4_list]
epilogue_list = [sentence_5_list, sentence_6_list]

# a book that contains chapters that contains sentences
book_list = [chapter_1_list, chapter_2_list, epilogue_list]

# want to see the goofy story backward?
book_list.reverse()
Enter fullscreen mode Exit fullscreen mode
Indexing Nested Lists

What if we wanted the 3rd item of the 4th list of the 1st list? Remember indexing? We can index nested lists too! It looks like this home_list[-1][3][21]. This would read something like “I want the last list in home_list. Then I want the item from index position 3 or the 4th item in that list. Now that I have that list, I want the object from index 21.” Try the below code with your nested list practice. Can you guess what it is before you run the code?

# get 2nd item from booklist, then 2nd item from that item, then 2nd item from that item
print(book_list[1][1][1])

# get 1st item from booklist, then the third from last item from that item, then 3rd item from that item
print(book_list[0][-3][2])
Enter fullscreen mode Exit fullscreen mode

Getting indices from nested lists can be confusing. Try reading them one index at a time and that should help. There’s really no limit to how many indices there can be other than the capability of the computer.

Were nested lists hard to understand? If so, don’t be hard on yourself. They’re a more advanced concept. You can absolutely keep coding and come back to these later.

Let’s Build Mad Libs

Picture of a 1982 mad lib: the magic computers: today, every student has a computer small enough to fit in his
Mad Libs are stories with words removed and replaced by blanks where you get to fill in the words and make a goofy story. Typically, the blanks are labeled and meant for certain types of words like verbs or adjectives. For this, we will make some lists, then choose words based on an index.

# make some lists of available words
verbs_list = ["yelled", "swam", "vanished", "kicked", "slept", "questioned", "scattered", "escaped", "chased", "jumped"]
adjectives_list = ["slimy", "gooey", "jumpy", "melted", "damaged", "fierce", "victorious", "sparkling", "rotten", "fluffy"]
nouns_list = ["donkey", "sidewalk", "zebra", "cactus", "playground", "toothbrush", "celery stalk", "umbrella", "bottle of poison", "ghost"]
adverbs_list = ["seemingly", "suspiciously", "foolishly", "greedily", "famously", "viciously", "awkwardly", "cleverly", "recklessly", "frantically"]

# get some user input
your_name = input("What's your name?").title()
num = int(input("Give a number 1-10"))
index = num - 1

# Publish your story using indices
print(your_name, adverbs_list[index], verbs_list[index], "on a", nouns_list[index], "in a", nouns_list[index-1])
Enter fullscreen mode Exit fullscreen mode

First we made our lists. Then we ask a user for their name and a number. We forced the number input to be an integer because it is a string by default. Next, we subtract 1 from the number they gave because in most programming languages we start counting at 0. Lastly, we used a print statement and list indexing to build our story.

This story is less than perfect. The strings in the print statement don’t always work because those words should change based on the chosen words from the lists. Still, this does show us a way to use lists and how to use indices. I bet you know enough to use code to help make decisions on which words to use. Do you remember what kind of statements we use to make decisions?

All of our words are hard-coded and it really would be better if they were filled in randomly. Later, we will go over how to make this into a random sentence generator.

Let’s Build a Better Coin-Flipping Game

Black person flipping a coin. The coin goes up a little before the it falls back to the person's hand
Do you recall how we talked about making a functional program then adding features later? We’re going to do that again. Our first rendition of this coin-flipping game was only a few lines then we added scoring. Now, we’re going to use lists to make this game even better.

rounds_won = 0  # start with 0 at beginning
rounds_lost = 0  # start with 0 at beginning
total_rounds = 0  # start with 0 at beginning
coin_landed_possibilities_list = ["heads", "tails"]

game_results_list = []  # starting a list to keep track of results

while total_rounds < 3:
    your_choice = input("Heads or Tails?").lower()
    coin_landed = coin_landed_possibilities_list[0]  # you can change this index
    if coin_landed == your_choice:
        print("You win this round")
        rounds_won = rounds_won + 1
        game_results_list.append("won")
    else:
        print("You lost this round")
rounds_lost = rounds_lost + 1
        game_results_list.append("lost")
total_rounds = total_rounds + 1

# calculate who won
if total_rounds == 3 and rounds_won >= 2:
    print("You win! You got best 2 out of 3")
else:
    print("You lose! Computer got best 2 out of 3")

# print results summary
print("summary of games:", game_results_list)
Enter fullscreen mode Exit fullscreen mode

This is a little better, right? We can keep track of our wins and losses with game_results_list. The coin_landed is no longer a string, but it is still hardcoded. The coin is always going to land on heads unless you changed it to a different index. Later, when we go over modules, we’ll talk about how to make coin_landed random. We’ll also talk about how to code a fix for what happens if someone types in something you don’t expect, like “kitties jumping on a trampoline.”. In reality, we know people are unlikely to type that, but they may type “hedds” or “tales”.

Did you see how we started that empty list? We call this “initializing a list”. It’s very much like getting out a piece of paper to start a list. You want to start or initialize this list so that it is ready for you to add things to it later.

Why lists and when to use them?

Lists allow us to categorize things by similarities and they work well with loops. Now would be a great time to go back to the loop section to see if you can make those fake list examples into real lists that work. Don’t forget lists are ordered or numbered. This helps us when creating, reading, updating, and deleting things because we can specify exactly where you want these actions to take place.


Do you remember?

Here's some practice challenges. Let’s practice what we’ve learned so far. Go ahead and comment on this post with your answers. Do you remember? If not, you can always go back to read sections again.

Give an example of a list, then follow these steps

  1. Make a list of something you might do in real life
  2. Get rid of the second to last item
  3. Flip the order of your list
  4. Make everything in your list uppercase
  5. Add something to the end of the list
  6. Add something to the middle of the list using the max index
  7. Flip the order of your list
  8. Add an item at position 1
  9. Empty your list

Show us:

# what your beginning list was

# the code you made

# the list you ended up with. 

Enter fullscreen mode Exit fullscreen mode
  • Was there anything that didn’t work? Do you know why?

Can You Fix What’s Wrong with This?

There may be more than one way to fix each line of code.

drawer_top = [voltage tester. wire caps, electrical tape,
drawer_middle = (1/4 inch sockets, ratchet. 1/2 inch sockets]
drawer_bottom = [rope, tape, zip ties,]
tool_box = [drawer_top". drawer_mid". drawer_bottom",}

drawer_left = [safety glasses| gloves| mask| ear plugs]
drawer_right = [hammer/ stud finder/ pencil/ scribe,]
work_bench = [drawer_left, drawer_right]

garage_list = [work_bench tool box, shelf]

# I need a 1/2 inch socket to take tire off bike
garage_list[2]{2][3)
Enter fullscreen mode Exit fullscreen mode

How would you read that last line out loud?

Go Ahead! You can build a game of chance

Using the coin-flipping game as an example, try making something like Rock Paper Scissors. Remember, to make the game work first, then add the extra stuff like lists and scoring. If something doesn’t work, no worries that’s normal. Go back to the How Do I Code? Error section for help figuring out the errors.

# scoring for a game using lists
Enter fullscreen mode Exit fullscreen mode

Thanks to @ceeoreo for allowing use of their beautiful name.

All of my gratitude to @yechielk for reviewing yet another post. If you like learning about how ethics and programming go together from a Talmudic perspective, check out their newsletter and book.

💖 💪 🙅 🚩
vickilanger
Vicki Langer

Posted on January 6, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related