##

# Python Programming: Sets and Tuples

## Learning Objectives

After this lesson, you will be able to:

- Perform common actions with sets.
- Perform common actions with tuples.
- Know when to use different data structures.

Teaching Tips:

- Quickly overview these; perhaps write them on the board.

## Discussion: Lists

Here are some lists:

    unique_colors = ["red", "yellow", "red", "green", "red", "yellow"]
    subscribed_emails = ["mary@gmail.com", "opal@gmail.com", "mary@gmail.com", "sayed@gmail.com"]

What could be a problem here?

Talking Points:

- “Why, in the `subscribed_emails` list, would duplicate entries be a problem? Or unique colors having duplicates?”

Teaching Tips:

- You can guide students to think about deduplication and the need to ensure unique values, thus dovetailing into sets

## Introducing Sets

Lists:

    unique_colors_list = ["red", "yellow", "red", "green", "red", "yellow"]
    subscribed_emails_list = ["mary@gmail.com", "opal@gmail.com", "mary@gmail.com", "sayed@gmail.com"]

Sets: Lists without duplicates!

    unique_colors_set = {"green", "yellow", "red"}
    subscribed_emails_set = {"mary@gmail.com", "opal@gmail.com", "sayed@gmail.com"}

- Notice the `[]` versus the `{}`.

Talking Points:

- Refresh memories that a list is a collection of elements, contained within square brackets `[]`:

- “However, there is a specific version of a list called a set. What makes a set different is that all of the elements in a set must be unique. That is to say, nothing can appear more than once in a set.” Sets have curly braces.

## How Can We Make a Set?

Making a set via a list - Python removes duplicates automatically.

    my_set = set(a_list_to_convert)

    # In action:
    unique_colors_list = ["red", "yellow", "red", "green", "red", "yellow"]
    unique_colors_set = set(unique_colors_list)
    # => {"green", "yellow", "red"}

    # Instead of passing a list in (a_list_to_convert), we could just type it:
    my_set_2 = (["enter", "list", "here"])

    # In action:
    unique_colors_set_2 = set(["red", "yellow", "red", "green", "red", "yellow"])
    # => {"green", "yellow", "red"}

Making a set directly, in curly braces:

    colors = {"red", "orange", "yellow", "green", "blue", "indigo", "violet"}

Talking Points:

- “Creating a set is easy; we just need to use the `set()` method like this.”

- “Because we had two `red`s, Python removed the extra one for us.”

Teaching Tips:

- Point out the difference between parentheses, brackets, and curly braces.

## Important Note: Sets

Lists are always in the same order:

- `my_list = ["green", "yellow", "red"]` is always going to be`["green", "yellow", "red"]`
- `my_list[0]` is always `"green"`; `my_list[1]` is always `"yellow"`; `my_list[2]` is always `"red"`.

Sets are not! Like dictionaries, they’re in any order.

- `my_set = {"green", "yellow", "red"}` could later be `{"red", "yellow", "green"}`!
- `my_set[0]` could be `"green"`, `"red"`, or `"yellow"` - we don’t know!

We cannot do: `print(my_set[0])` - it could be anything! Python won’t let us.

## We Do: Creating a Set from a List

Let’s pull up a new `set_practice.py` file and make some sets!

- Make a list `clothing_list` containing the main color of your classmates’ clothing.
- Using `clothing_list`, make a set named `clothing_set`.
- Use a `for` loop to print out both `clothing_list` and `clothing_set`.
- Try to print an index!

Teaching Tips:

- Run through this with them - make sure they are following along to practice typing the syntax.
- Be prepared to refresh memories on `for` loops.
- Try to print an index - reinforce that sets are in any order.

## We Do: Adding to a Set

How do we add more to a set?

    # In a list:
    clothing_list.append("red")

    # In a set
    clothing_set.add("red")

`add` vs `append` - this is because we can’t guarantee it’s going at the end!

Let’s a few colors to `clothing_list` and `clothing_set`, then print them.

- What happens if you add a duplicate?

Talking Points:

- Continue locally with the list and set they created previously - do this with them!
- Try to add a duplicate, then print. Call out that it just doesn’t appear, since sets can’t have duplicates.

## We Do: Removing from a List and a Set

Remember, lists are always the same order: `["green", "yellow", "red"]`.

- `my_list[0]` is always “green”.

Remember, sets are not!

- With the set `{"green", "yellow", "red"}`, `my_set[0]` could be `green`, `red`, or `yellow`.

The same way, we need to be careful about removal:

    # In a list:
    clothing_list.pop() # Removes and returns the last item in the list.
    clothing_list.pop(0) # Removes and returns a specific (here, the first) item in the list.

    # In a set
    clothing_set.pop() # No! This is unreliable! The order is arbitrary.
    clothing_set.pop(0) # No! Python throws an error! You can't index sets.
    clothing_set.remove('red') # Do this! Call the element directly!

Teaching points:

- Walk through these. `pop` from the set to show that it’s unreliable.

Talking Points:

- Address that for lists, the order matters. For sets, it’s irrelevant, so `pop` returns an arbitrary element.
- Discuss the difference between `remove` and `pop`.

## Quick Review: Sets vs. Lists

Lists:

- The original, normal object.
- Created with `[]`.
- `append()`, `insert(index)`, `pop()`, `pop(index)`.
- Duplicates and mutable.

Sets:

- Lists without duplicates.
- Created with `{}` or with `set(my_list)`.
- `add()` and `remove(element)`.

Teaching Tips:

- A code review for all of these are on the next slide.
- Review these - on this slide, do a check for conceptual understanding.

## Quick Review: Sets vs. Lists

    ### Creation ###
    # List
    my_list = ["red",  "yellow", "green", "red"]
    # Sets
    my_set = {"red",  "yellow", "green"}
    my_set2 = set(my_list)
    my_set = set(a_list_to_convert)

    ### Appending a New Value ###
    my_list.append("blue")
    my_set.add("blue")

    ### Appending a Duplicate ###
    my_list.append("blue")
    # => my_list = ["red",  "yellow", "green", "red", "blue",  "blue"]
    my_set.add("blue")
    # => my_set = {"red",  "yellow", "green", "blue"}

    ### Removing items: ###
    my_list.pop(1)
    my_set.remove("red")

Teaching Tips:

- Do a quick check for understanding.
- Go through each example.

Talking Points:

- Point out again the difference in syntax, especially with curly braces.
- Reinforce `pop` being unreliable.

## Discussion: Immutability Thoughts

A set is a type of list which doesn’t allow duplicates.

What if, instead, we have a list we don’t want to change?

    rainbow_colors = ("red", "orange", "yellow", "green", "blue", "indigo", "violet")

We don’t want:

    rainbow_colors[0] = ("gray")
    ## Gray's not in the rainbow!
    rainbow_colors.pop()
    ## We can't lose violet!
    rainbow_colors.append("pink")
    # Pink's not in the rainbow!

We want `rainbow_colors` to be immutable - the list cannot be changed.

How we do that in Python?

Talking Points:

- We’re done with sets.
- Immutable means “unchangeable”.

## Introducing: Tuples

Sets are one specific type of list.

- No duplicates, but mutable.

Tuples are another specific type of list.

- Duplicates, but immutable.
- A list that cannot be changed.

    rainbow_colors_tuple = ("red", "orange", "yellow", "green", "blue", "indigo", "violet")

When should you use a tuple?

- When you need data protection through immutability.
- When you never want to change the list.

Talking Points:

- Point out that with tuples, duplicates are fine! Be clear that tuples are another kind of list, NOT a kind of set.
- Python offers a data structure that provides more secure usage than the wide power of a fully mutable list.
- The tuple is a kind of data structure that provides immutable values in a list.
- Once a tuple is created and assigned its elements, no changes can be made to the tuple.
- "Why? Isn’t it more useful to work with a list that allows us to change elements when necessary? Doesn’t this inflexibility make our code easier to break?
- “We will frequently need the power to create and edit lists, adding and removing items from them. In these instances, use a list.”

## Tuple Syntax

- Created with parentheses `()`.
- Access values via indices (like regular lists, but not like sets).

    rainbow_colors_tuple = ("red", "orange", "yellow", "green", "blue", "indigo", "violet")
    print(rainbow_colors[1])
    # Prints "orange"

- Tuples can be printed with a `for` loop (just like a set or list!).

    rainbow_colors_tuple = ("red", "orange", "yellow", "green", "blue", "indigo", "violet")

    for color in rainbow_colors_tuple:
      print(color)

Talking Points:

- Tuples work exactly like lists, except that, when you create a tuple, you use parentheses instead of square brackets.
- You can include anything you want, but, for now, we’ll add strings.

## We Do: Tuples

Let’s declare a tuple named `seasons` and set it to have the values `fall`, `winter`, `spring`, and `summer`. We’ll print the tuple and each value. Then we’ll try to reassign them (we can’t)!

Teaching Tips:

- Make sure they’re doing this with you.
- Print out each value directly with indexes. Then, use a `for` loop.
- Try to change values - pop, append, and direct reassignment.

Talking point:

- Remind them of the syntax - perhaps make sets and lists as well, so students can see them compared again.

## Quick Review: Sets, Tuples, Lists

List:

- The original, normal object: `["red", "red", "yellow", "green"]`.
- Has duplicates; mutable: `append()`, `insert(index)`, `pop()`, `pop(index)`

Set:

- List without duplicates: `{"red", "yellow", "green"}`.
- Mutable: `add()` and `remove(element)`

Tuple:

- Has duplicates, but immutable: You can’t change it!
- `("red", "red", "yellow", "green")` will always be `("red", "red", "yellow", "green")`.

Teaching Tips:

- A code review for all of these are on the next slide.
- Remind them about `add` vs `append` - this is because we can’t guarantee it’s going at the end!
- Review these - on this slide, do a check for conceptual understanding.
- Always reinforce the `[]` vs `{}` vs `()`
- Recap immutability.

## Quick Review: Sets, Tuples, Lists

    ### Creation ###
    # List
    my_list = ["red",  "yellow", "green", "red"]
    # Sets
    my_set = {"red",  "yellow", "green"}
    my_set2 = set(my_list))
    my_set = set(a_list_to_convert)
    # Tuples
    my_tuple = ("red",  "yellow", "green")

    ### Appending a New Value ###
    my_list.append("blue")
    my_set.add("blue")
    # Tuples -> You can't!

    ### Removing items: ###
    my_list.pop(1)
    my_set.remove("red")
    # Tuples -> You can't!

Teaching Tips:

- Do a check for understanding of the code syntax.
- Go through each example.

Talking Points:

- Recap the types of braces to create each; remove vs pop; append vs add.
- Remind students that they aren’t expected to be syntax experts - they can always look this up. Working programmers look things up every day on the job, but students have to know what things are and what to expect.

## Introducing Types

Variables certainly can hold a lot!

- Sets, tuples, and lists are easily confused.
- `type()` tells us what a variable is: set, tuple, list, dictionary, integer, string - anything!

Try it:

Talking Points:

- It’s useful to know what datatype a variable is and how to use it. This will work on anything.

Teaching Tips:

- Walk through each of these. It will recap the syntax as well as re-inforce using `type`. You might want to open the repl.it in a new window, as it’s a bit long.

Repl.it Note: This replit has:

    unique_colors = set(["red", "yellow", "green", "red"])
    print("unique_colors is", type(unique_colors))
    # --
    unique_colors_2 = ["red", "yellow", "green", "red"]
    print("unique_colors_2 is", type(unique_colors_2))
    # --
    unique_colors_3 = ("red", "yellow", "green", "red")
    print("unique_colors_3 is", type(unique_colors_3))
    # --
    my_number = 2
    print("my_number is", type(my_number))
    # --
    my_string = "Hello!"
    print("my_string is", type(my_string))

## You Do: List Types Practice

Create a local file, `sets_tuples.py`. In it:

- Create a list (`[]`), set (`{}`), and tuple (`()`) of some of your favorite foods.
- Create a second set from the list.

Next, in every list type that you can:

- Add `"pizza"` anywhere; append `"eggs"` to the end.
- Remove `"pizza"`.
- Re-assign the element at index `1` to be `"popcorn"`.
- Remove the element at index `2` and re-insert it at index `0`.
- Print the element at index `0`.

Print your final lists using a loop, then print their types. Don’t throw an error!

10 minutes

Teaching Tips:

- Give students time to do this - it’s a lot of syntax to go back through and find.
- Walk around the room to check for questions and offer help when needed.
- Once most of them have it, go over the answer. Make sure you remove pizza in the list, too.

## Summary and Q&A

We’ve learned two new types of lists:

Sets:

- A mutable list without duplicates.
- Handy for storing emails, usernames, and other unique elements.

    email_set = {'my_email@gmail.com', 'second_email@yahoo.com', "third_email@hotmail.com"}

Tuples:

- An immutable list that allows duplicates.
- Handy for storing anything that won’t change.

    rainbow_tuple = ("red", "orange", "yellow", "green", "blue", "indigo", "violet")

## Additional Reading

- Repl.it that recaps Tuples
- Python Count Occurrences of Letters, Words and Numbers in Strings and Lists-Video
- Storing Multiple Values in Lists
- Sets and Frozen Sets
- Sets
- Python Tuple
- Tuples
- Strings, Lists, Tuples, and Dictionaries Video
- Python Data Structures: Lists, Tuples, Sets, and Dictionaries Video