XClose

COMP0233: Research Software Engineering With Python

Home
Menu

Data structures

Nested Lists and Dictionaries

In research programming, one of our most common tasks is building an appropriate structure to model our complicated data. Later in the course, we'll see how we can define our own types, with their own attributes, properties, and methods. But probably the most common approach is to use nested structures of lists, dictionaries, and sets to model our data. For example, an address might be modelled as a dictionary with appropriately named fields:

In [1]:
UCL = {
    'City': 'London',
    'Street': 'Gower Street',
    'Postcode': 'WC1E 6BT'
}
In [2]:
Chapman_house = {
    'City': 'London',
    'Street': 'Southwood ln',
    'Postcode': 'N6 5TB'
}

A collection of people's addresses is then a list of dictionaries:

In [3]:
addresses = [UCL, Chapman_house]
In [4]:
addresses
Out[4]:
[{'City': 'London', 'Street': 'Gower Street', 'Postcode': 'WC1E 6BT'},
 {'City': 'London', 'Street': 'Southwood ln', 'Postcode': 'N6 5TB'}]

A more complicated data structure, for example for a census database, might have a list of residents or employees at each address:

In [5]:
UCL['people'] = ['Jeremy','Leonard', 'James', 'Henry']
In [6]:
Chapman_house["People"] = ["Graham", "David"]
In [7]:
addresses
Out[7]:
[{'City': 'London',
  'Street': 'Gower Street',
  'Postcode': 'WC1E 6BT',
  'people': ['Jeremy', 'Leonard', 'James', 'Henry']},
 {'City': 'London',
  'Street': 'Southwood ln',
  'Postcode': 'N6 5TB',
  'People': ['Graham', 'David']}]

Which is then a list of dictionaries, with keys which are strings or lists.

We can go further, e.g.:

In [8]:
UCL["Residential"] = False

And we can write code against our structures:

In [9]:
leaders = [place["People"][0] for place in addresses]
print(leaders)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[9], line 1
----> 1 leaders = [place["People"][0] for place in addresses]
      2 print(leaders)

KeyError: 'People'

This was an example of a 'list comprehension', which is used to get data of this structure, and which we'll see more of in a moment...

Exercise: a Maze Model.

Work with a partner to design a data structure to represent a maze using dictionaries and lists.

  • Each place in the maze has a name, which is a string.
  • Each place in the maze has zero or more people currently standing at it, by name.
  • Each place in the maze has a maximum capacity of people that can fit in it.
  • For each place in the maze, you can go from that place to a few other places, using a direction like 'up', 'north', or 'sideways'

Create an example instance, in a notebook, of a simple structure for your maze:

  • The living room can hold 2 people. Graham is currently there. You can go outside to the garden, or upstairs to the bedroom, or north to the kitchen.
  • From the kitchen, you can go south to the living room. It fits 1 person.
  • From the garden you can go inside to living room. It fits 3 people. David is currently there.
  • From the bedroom, you can go downstairs. You can also jump out of the window to the garden. It fits 2 people.

Make sure that your model:

  • Allows empty rooms.
  • Allows you to jump out of the upstairs window, but not to fly back up.
  • Allows rooms which people can't fit in.

As an example of a similar problem, the following code could be used to represent a collection of cities, each of which has a name, a maximum capacity, and potentially some people currently living there.

In [10]:
cities = [
    {"name": "London", "capacity": 8, "residents": ["Graham", "David"]},
    {"name": "Edinburgh", "capacity": 1, "residents": ["Henry"]},
    {"name": "Cardiff", "capacity": 1, "residents": []},
]

We can then check, for instance, how many people currently reside in the third city:

In [11]:
len(cities[2]["residents"])
Out[11]:
0