Skip to content
This repository has been archived by the owner on Oct 9, 2024. It is now read-only.

Commit

Permalink
Add section on dictionaries, and additional exercises.
Browse files Browse the repository at this point in the history
  • Loading branch information
simonkirbysimonkirby committed Nov 3, 2022
1 parent 104e686 commit b77c1c1
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 20 deletions.
173 changes: 173 additions & 0 deletions _episodes/04_dictionaries copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
---
layout: page
title: Dictionaries
order: 5
session: 1
length: 15
toc: true
---

## Learning Objectives

At the end of this lesson you will be able to:

- Identify and explain what a dictionary is
- Explain what makes a dictionary different to a list
- Understand the `key`: `value` relationship
- Create a dictionary containing simple values
- Update values in a dictionary

## Key points

- A dictionary stores key-value pairs.
- Dictionaries are unordered.
- Dictionaries are immutable.

## Introduction

Lists and arrays are useful, but don’t cover every use case. One of Python’s best features is its “dictionary” data structure. Whereas a list or array is simply a collection of elements, a dictionary supports key-value storage of data. Put into plain english, it lets you store and retrieve data values by name.

## Create a dictionary

Let’s create and use a simple dictionary of scientist's birth years to illustrate this:

~~~
birth_years = {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833}
print(birth_years)
~~~
{: .language-python}

~~~
{'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833}
~~~
{: .output}

Here, 'Newton', 'Darwin', 'Einstein' and 'Nobel' are keys, and the years are values. Keys and values form a pairwise mapping, allowing the retrieval of a value via the value's key.

We can retrieve a value from a dictionary by entering the correct key for this value. We do this using the following syntax:

~~~
value_we_want = dictionary['key_of_value_we_want']
~~~
{: .language-python}

This is similar to accessing a value stored in a list. However, the key does not have to be an integer.

## Retrieve a value

> Retrieve the birth year for Isaac Newton from the dictionary of birth years.
>
> > ## Solution
> > ~~~
> > birth_years = {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833}
> > birth_years['Newton']
> > ~~~
> > {: .language-python}
> > ~~~
> > 1642
> > ~~~
> > {: .output}
> {: .solution}
{: .challenge}
## Altering a dictionary
Similar to lists, dictionaries are mutable. We can add a value to a dictionary, using a key:
~~~
birth_years = {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833}
birth_years['Turing'] = 1612
print(birth_years)
~~~
{: .language-python}
~~~
{'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833, 'Turing': 1612}
~~~
{: .output}
Oops, we made a mistake there. Turing was actually born in 1912. We can update a value using a key.
Turing's birthdate above is actual incorrect. Values may be overwritten by re-assignment:
~~~
birth_years = {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833, 'Turing': 1612}
birth_years['Turing'] = 1912
print(birth_years)
~~~
{: .language-python}
~~~
{'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833, 'Turing': 1912}
~~~
{: .output}
## Add your own scientists to a dictionary
> Add two more scientist's birth years to our dictionary of birth years.
>
> > ## Solution
> > ~~~
> > birth_years = {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833, 'Turing': 1612}
> > birth_years['Curie'] = 1867
> > birth_years['Franklin'] = 1920
> > print(birth_years)
> > ~~~
> > {: .language-python}
> > ~~~
> > {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833, 'Turing': 1612, 'Curie': 1867, 'Franklin': 1920}
> > ~~~
> > {: .output}
> {: .solution}
{: .challenge}
## Retrieve all keys and values
Dictionaries contain a number of in-built methods that allow you to easily access the data contained within. These methods are automatically attached to every dictionary.
~~~
birth_years = {'Newton': 1642, 'Darwin': 1809, 'Einstein': 1979, 'Nobel': 1833, 'Turing': 1612, 'Curie': 1867, 'Franklin': 1920}
birth_years.keys()
~~~
{: .language-python}
~~~
dict_keys(['Newton', 'Darwin', 'Einstein', 'Nobel', 'Turing', 'Curie', 'Franklin'])
~~~
{: .output}
Similarly for values:
~~~
birth_years.values()
~~~
{: .language-python}
~~~
dict_values([1642, 1809, 1979, 1833, 1612, 1867, 1920])
~~~
{: .output}
We can convert these to lists:
~~~
list(birth_years.values())
~~~
{: .language-python}
~~~
[1642, 1809, 1979, 1833, 1612, 1867, 1920]
~~~
{: .output}
And finally, retrieve the key, value pairs together, forming a list of tuples:
~~~
list(birth_years.items())
~~~
{: .language-python}
~~~
[('Newton', 1642), ('Darwin', 1809), ('Einstein', 1979), ('Nobel', 1833), ('Turing', 1612), ('Curie', 1867), ('Franklin', 1920)]
~~~
{: .output}
20 changes: 0 additions & 20 deletions _episodes/04_dictionaries.md

This file was deleted.

121 changes: 121 additions & 0 deletions _episodes/07_additional_exercises.md.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
layout: page
title: Additional exercises
order: 8
session: 1
length: 20
toc: true
---

## Swapping the contents of variables

> Explain what the overall effect of this code is:
>
> ~~~
> left = 'L'
> right = 'R'
>
> temp = left
> left = right
> right = temp
> ~~~
> {: .language-python}
>
> Compare it to:
>
> ~~~
> left, right = right, left
> ~~~
> {: .language-python}
>
> Do they always do the same thing?
> Which do you find easier to read?
>
> > ## Solution
> > Both examples exchange the values of `left` and `right`:
> >
> > ~~~
> > print(left, right)
> > ~~~
> > {: .language-python}
> >
> > ~~~
> > R L
> > ~~~
> > {: .output}
> >
> > In the first case we used a temporary variable `temp` to keep the value of `left` before we
> > overwrite it with the value of `right`. In the second case, `right` and `left` are packed into a
> > [tuple]({{ page.root }}/reference.html#tuple)
> > and then unpacked into `left` and `right`.
> {: .solution}
{: .challenge}
## Turn a String into a List
> Use a for-loop to convert the string "hello" into a list of letters:
>
> ~~~
> ["h", "e", "l", "l", "o"]
> ~~~
> {: .language-python}
>
> Hint: You can create an empty list like this:
>
> ~~~
> my_list = []
> ~~~
> {: .language-python}
>
> > ## Solution
> > ~~~
> > my_list = []
> > for char in "hello":
> > my_list.append(char)
> > print(my_list)
> > ~~~
> > {: .language-python}
> {: .solution}
{: .challenge}
## Reverse a String
> Knowing that two strings can be concatenated using the `+` operator,
> write a loop that takes a string
> and produces a new string with the characters in reverse order,
> so `'Newton'` becomes `'notweN'`.
>
> > ## Solution
> > ~~~
> > newstring = ''
> > oldstring = 'Newton'
> > for char in oldstring:
> > newstring = char + newstring
> > print(newstring)
> > ~~~
> > {: .language-python}
> {: .solution}
{: .challenge}
## Fixing and Testing
> Fix `range_overlap`. Re-run `test_range_overlap` after each change you make.
>
> > ## Solution
> > ~~~
> > def range_overlap(ranges):
> > '''Return common overlap among a set of [left, right] ranges.'''
> > if not ranges:
> > # ranges is None or an empty list
> > return None
> > max_left, min_right = ranges[0]
> > for (left, right) in ranges[1:]:
> > max_left = max(max_left, left)
> > min_right = min(min_right, right)
> > if max_left >= min_right: # no overlap
> > return None
> > return (max_left, min_right)
> > ~~~
> > {: .language-python}
> {: .solution}
{: .challenge}

0 comments on commit b77c1c1

Please sign in to comment.