3_NestedDataStructures.ipynb 24.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to Python Programming"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
14
    "## 3. Nested Data Structures"
15 16 17 18 19 20
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
21
    "You now know about the most commonly-used Python data types. There are more, each with characteristics suited to a particular task or situation and, if you like, you can make your own as well. You can see the full list of built-in data structures here: https://docs.python.org/3.5/library/stdtypes.html. You should also have an idea of the ways that you can repeat actions on lists and dictionaries with `for` loops, as well as take decisions based on data using `if` statements. This knowledge and these skills can be applied to some quite sophisticated programming. "
22 23 24 25 26 27 28 29 30
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One other key to writing effective programs is the ability to encapsulate your data and allow them to be accessed and analysed in a way that is efficient and appropriate. If you don't take the time to consider the best way to capture, store, and access your data, you can end up writing programs that are much more complicated and error-prone than they need to be. This can cost you a lot more time in the future. As with any project, a little time spent planning at the beginning can save a lot of time later on."
   ]
  },
31 32 33 34 35 36 37 38 39 40 41
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### _Warmup exercise_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
42
    "Imagine, you woke up this morning and you had several ideas for things you want to do today, each can be described by a word or a short sentence. You want to write down those ideas (store them in Python), which data type is in your opinion best suited to host all of that data?\n",
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    "- an integer\n",
    "- a string\n",
    "- a list\n",
    "- a group\n",
    "- a dictionary\n",
    "- other"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[write down answer]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After compiling your collection of all the things you want to get done today, you realized that they can and should be categorized into different projects like 'work', 'home' etc.\n",
    "Given your response to the question above, how would you store your data into multiple levels?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[write down answer]"
   ]
  },
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Combining Structures"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Often, datasets are best encapsulated by combining the basic data structures together to form larger, well-organised collections that fit the characteristics of the dataset. This combination of multiple data structures is often referred to as 'nesting'. Getting used to dealing with these structures as they grow larger and more complicated can take a bit of time, but it becomes easier with practise and is very important for good programming."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To make this easier to understand, let's begin with some examples. Let's say that you teach seminars to three different groups of students, and you are writing a program that will keep track of the names of these students. For each seminar group, you could store the names in a list."
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
96
   "execution_count": null,
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "GroupA = ['Sarah', 'Richard', 'Matthew', 'Fiona', 'Sally', 'Samuel']\n",
    "GroupB = ['Richard', 'Sally', 'Sandy', 'Peter', 'Rebecca', 'Steve', 'Lesley', 'Stuart']\n",
    "GroupC = ['Simon', 'Laura', 'Gareth', 'Alan', 'Helen']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, you might want to go through all of the names for all of the groups. You could write three loops:"
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
116
   "execution_count": null,
117 118 119
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
120
   "outputs": [],
121 122 123 124 125 126 127
   "source": [
    "for student in GroupA:\n",
    "    print(student)"
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
128
   "execution_count": null,
129 130 131
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
132
   "outputs": [],
133 134 135 136 137 138 139
   "source": [
    "for student in GroupB:\n",
    "    print(student)"
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
140
   "execution_count": null,
141 142 143
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
144
   "outputs": [],
145 146 147 148 149 150 151 152 153 154 155 156 157 158
   "source": [
    "for student in GroupC:\n",
    "    print(student)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Teaching can be quite time-consuming at the best of times, and this is getting quite repetitive! Of course, it gets even worse if you teach even more groups, or if you are working with a larger dataset of some other kind. Instead, you could combine the lists together into a single list,"
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
159
   "execution_count": null,
160 161 162 163 164 165 166 167 168 169 170 171
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "AllGroups = GroupA + GroupB + GroupC"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
172
    "but you might not want to lose track of which students belong to which class. So instead, it is a good idea to store the individual lists as entries in another data structure that can be processed iteratively just like the lists themselves. We have a few options here, but let's begin with a list of lists - where each entry in the list is itself another list:"
173 174 175 176
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
177
   "execution_count": null,
178 179 180 181 182 183 184
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "AllGroups = [ GroupA , GroupB , GroupC ]\n",
    "# This is equivalent to the below, but much easier to read!\n",
185 186
    "AllGroups = [ ['Sarah', 'Richard', 'Matthew', 'Fiona', 'Sally', 'Samuel'] ,\n",
    "              ['Richard', 'Sally', 'Sandy', 'Peter', 'Rebecca', 'Steve', 'Lesley', 'Stuart'] ,\n",
187 188 189 190 191 192 193 194 195 196 197 198
    "              ['Simon', 'Laura', 'Gareth', 'Alan', 'Helen'] ]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, to work through all the names of all the students, we need to iterate over each entry in the top-level list `AllGroups` and, because we know that each of these entries is itself a list, iterate over the entries of this second-level list as well. As you will remember from the previous worksheet, iterating over a list can be acheived with a `for` loop. In this case, to iterate over everything in our two-level nested lists we will just use two nested `for` loops."
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
199
   "execution_count": null,
200 201 202
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
203
   "outputs": [],
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
   "source": [
    "for group in AllGroups:\n",
    "    for student in group:\n",
    "        print(student)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great! So now we can get a full list of our students' names, without writing an individual `for` loop for every class we teach. But we have lost some information in the process, because we can't tell by looking at the list above where the names for one class end and another begin."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
221
    "#### _Exercise 3.1_"
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What other combination of data structures might we use to encapsulate our class lists? Before you look at the next section, try to figure out what the best nested structure might be for this data."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Choosing An Appropriate Structure"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Consider what information we have for each class: it has a name (A, B, C) and a list (the student names). This sounds a lot like the kind of information that is best stored in a dictionary - we have a key (the group name) and an associated value (the list of students). So, we can combine the data into a second type of nested structure: a dictionary of lists."
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
247
   "execution_count": null,
248 249 250 251 252
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
253 254
    "AllGroups = { 'Group A': GroupA,\n",
    "              'Group B': GroupB,\n",
255 256 257 258 259 260 261 262 263 264 265 266
    "              'Group C': GroupC }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have produced this dictionary, we can iterate over it, and each of the lists contained within, using a verysimilar nested `for` loop structure to the one we had before for our list of lists:"
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
267
   "execution_count": null,
268 269 270
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
271
   "outputs": [],
272 273 274 275 276 277 278 279 280 281 282
   "source": [
    "for group in AllGroups.keys():\n",
    "    print(group)\n",
    "    for student in AllGroups[group]:\n",
    "        print(student)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
283
    "Things have improved a little. Now we are printing the name of the group each time we start a new one, but these group names are not in alphabetical order (unless you got lucky - remember that the order that keys are accessed from a  dictionary using `.keys()` can't be relied upon or predicted, or you're using Python 3.6) and they're quite hard to spot amongst the names of the students. To make sure that you understand what just happened, let's take a look at that code block above step-by-step."
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```Python\n",
    "for group in AllGroups.keys():\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, we create a `for` loop to iterate over every key in the dictionary `AllGroups`. Hopefully, you recognise this from the previous worksheet. At the start of each iteration in this `for` loop the value of the variable `group` will be assigned as the next key from the dictionary. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```Python\n",
    "    print(group)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We print the group name before starting to loop through the list of student names."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```Python\n",
    "    for student in AllGroups[group]:\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we are defining the second `for` loop, assigning the value of the variable `student` with the name of the next student in the list for the current group. Here, remember that `AllGroups[group]` returns the value associated with the key `group` in the dictionary `AllGroups`. `group` is whichever group name we are currently dealing with in this iteration of the first for loop. That is, if the first key returned by `AllGroups.keys()` is `'Group B'`, then:\n",
    " - `group` has been assigned the value `'Group B'`,  \n",
    " - so `AllGroups[group]` is currently equivalent to `AllGroups['Group B']`,  \n",
    " - which returns the value associated with the key `'Group B'`, which is the list `GroupB`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you followed that, then you will understand that the last line"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```Python\n",
    "        print(student)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "will print out the name of the next student in the list referred to by `AllGroups[group]`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The order of the four lines of code above is very important. Consider what would happen if you put the `print(group)` line within the second `for` loop. You can even give it a try and see if your hypothesis was right."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
371
    "#### _Exercise 3.2_"
372 373 374 375 376 377 378
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As mentioned before, there are a couple of problems with the output that we are getting from the code block above. Try to find a way to make the names of the groups stand out a bit more from the names of the students.  \n",
379
    "After you have achieved that, see if you can find a way to explicitly control the order in which the groups are displayed, so that they appear alphabetically - Group A, Group B, Group C."
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### More Nesting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is one more type of nested data structure that we need to consider. To help with this, we need to expand the dataset slightly. Being the diligent and conscientious tutor that you are, you spent hours preparing, running and marking an assessment for each seminar group. You have collected the results, which are given below:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Group A__  \n",
    "\n",
    "| Student | Mark |\n",
    "|---------|------|\n",
    "| Sarah   | 78   |\n",
    "| Richard | 65   |\n",
    "| Matthew | 53   |\n",
    "| Fiona   | 71   |\n",
    "| Sally   | 43   |\n",
    "| Samuel  | 80   |\n",
    "\n",
    "__Group B__  \n",
    "\n",
    "| Student | Mark |\n",
    "|---------|------|\n",
    "| Richard | 57   |\n",
    "| Sally   | 89   |\n",
    "| Sandy   | 75   |\n",
    "| Peter   | 77   |\n",
    "| Rebecca | 62   |\n",
    "| Steve   | 71   |\n",
    "| Lesley  | 75   |\n",
    "| Stuart  | 80   |\n",
    "\n",
    "__Group C__  \n",
    "\n",
    "| Student | Mark |\n",
    "|---------|------|\n",
    "| Simon   | 47   |\n",
    "| Laura   | 91   |\n",
    "| Gareth  | 74   |\n",
    "| Alan    | 61   |\n",
    "| Helen   | 74   |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we have pairs of data for each group - the student's name and their mark. We want to store this data in a way that keeps all of the results together for all of the groups, but allows the data for each group and individual student to be accessed independently. If you first consider the groups individually - pairs of names and marks - this type of dataset is clearly best represented as a dictionary. And, for the reasons discussed before, we know that storing each group and it's data in a dictionary that can be accessed by the name of the group is a good idea too. So, to store all of this information we want to build a dictionary of dictionaries. First, let's create our individual dictionaries for each group."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
446
    "__Note__ If you're not working interactively with the IPython Notebook version of this workbook, you could be about to do a lot of typing to enter all this data yourself. To save you the trouble, the data is available as a file from [GitHub](https://git.embl.de/grp-bio-it/ITPP/blob/master/seminarGroupMarks.txt). However, we won't cover how to read data from a file until the next worksheet. So for now, you can either skip ahead to find out how to do it (but make sure that you come back later!), read through and try to follow along without typing everything in yourself (you might find it difficult to understand exactly what's going on this way), or type/copy the whole lot. Sorry!"
447 448 449 450
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
451
   "execution_count": null,
452 453 454 455 456
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
457 458 459 460 461
    "GroupA_Results = { 'Sarah'  : 78 ,\n",
    "                   'Richard': 65 ,\n",
    "                   'Matthew': 53 ,\n",
    "                   'Fiona'  : 71 ,\n",
    "                   'Sally'  : 43 ,\n",
462
    "                   'Samuel' : 80 }\n",
463 464 465 466 467 468 469
    "GroupB_Results = { 'Richard': 57 ,\n",
    "                   'Sally'  : 89 ,\n",
    "                   'Sandy'  : 65 ,\n",
    "                   'Peter'  : 77 ,\n",
    "                   'Rebecca': 62 ,\n",
    "                   'Steve'  : 71 ,\n",
    "                   'Lesley' : 75 ,\n",
470
    "                   'Stuart' : 80 }\n",
471 472 473 474
    "GroupC_Results = { 'Simon'  : 47 ,\n",
    "                   'Laura'  : 91 ,\n",
    "                   'Gareth' : 74 ,\n",
    "                   'Alan'   : 61 ,\n",
475 476 477 478 479 480 481
    "                   'Helen'  : 74 }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
482
    "Now, we can create a top-level dictionary with three entries — one for each group. The keys are the names of the groups, and the associated values the dictionary of results for the students in the groups."
483 484 485 486
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
487
   "execution_count": null,
488 489 490 491 492
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
493 494
    "AllGroupResults = { 'Group A' : GroupA_Results ,\n",
    "                    'Group B' : GroupB_Results ,\n",
495 496 497 498 499 500 501 502 503 504 505 506
    "                    'Group C' : GroupC_Results }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All of the assessment results are stored in a single dictionary. You can access the results for a particular group quite easily, using the approach introduced earlier:"
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
507
   "execution_count": null,
508 509 510
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
511
   "outputs": [],
512 513 514 515 516 517 518 519 520 521 522 523 524
   "source": [
    "AllGroupResults['Group C']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But what if you want to know how a particular student scored? How can we access the value for a particular key in the dictionary that is itself the value associated with a key at the top level? Well, above we accessed the value associated with the key `'Group C'` using the syntax `dictionary[key]`. In this case, we know that that returns another dictionary. So, if we now want to get the score for a particular student in that group, we just query that dictionary in the same way."
   ]
  },
  {
   "cell_type": "code",
Toby Hodges's avatar
Toby Hodges committed
525
   "execution_count": null,
526 527 528
   "metadata": {
    "collapsed": false
   },
Toby Hodges's avatar
Toby Hodges committed
529
   "outputs": [],
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
   "source": [
    "AllGroupResults['Group C']['Laura']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If this looks strange to you, or you're struggling to make sense of it, remember that Python will interpret the line from left to right:  \n",
    "- first, it comes across the variable `AllGroupResults`, which it identifies as a dictionary  \n",
    "- then, it sees that you want to extract the value associated with the key `'Group C'`  \n",
    "- it fetches that value, `AllGroupResults['Group C']`, and identifies it as a dictionary, too  \n",
    "- then it moves on to the last part of the line, `['Laura']`, and recognises that you want to extract the value associated with the key `'Laura'` in the dictionary given by `AllGroupResults['Group C']`  \n",
    "- finally, it fetches that value and returns it."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
550
    "#### _Exercise 3.3_"
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using what you've learned above about iterating over nested data structures, write a program that will loop through every student in every group and print out their mark. Make sure that you can identify in the output of your program, the group that each student name has come from.  \n",
    "Once you have acheived this, try changing the behaviour of your program to calculate and output the (mean) average mark for each group."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Scaling Up"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Being able to store and access data in a suitable structure is all well and good, but the benefits of it become more obvious when you have a repetitive task that you need to complete. This is especially true when you consider this kind of problem applied to a dataset much larger than the toy examples that we are working with here. What if you ran a whole faculty, with tens of different seminar groups, containing hundreds of students, who each take multiple exams/assesments?!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this kind of situation, manual entry of the data isn't practical. Instead, it is much more helpful to be able to read the information that you need from a file. Working with input from other sources, and output of results, will be covered in the next worksheet."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
586
    "#### _Exercise 3.4_"
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The exercises in the next worksheet are designed to be more challenging for newcomers to programming/Python. In preparation for this, here is one last exercise designed to consolidate the things that you have learned so far.  \n",
    "Now that you have finished marking your students' assessments, you need to let them know how they got on. Write a program that will print out the body of an email to each student according to this template:\n",
    "\n",
    "Dear _[name]_,  \n",
    "I have finished marking the assessment for your seminar group, _[group name]_. You scored _[their mark]_.  \n",
    "_[an additional comment according to their score (see below)]_  \n",
    "Kind regards,  \n",
    "_[your name]_\n",
    "\n",
    "The additional comment on the third line of the email should be chosen according to the mark that they scored on the assessment.  \n",
    "\n",
    "| Score range | Comment                                                                |\n",
    "|-------------|------------------------------------------------------------------------|\n",
    "| <60:        | 'You must try harder next time. Are you taking this course seriously?' |\n",
    "| 60-79:      | 'Well done, that's a good score.'                                      |\n",
    "| >79:        | 'Congratulations! That's an excellent score!'                          |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course, the potential for nested data structures doesn't stop at two-level lists of lists, or lists of dictionaries, or dictionaries of lists, or dictionaries of dictionaries! Depending on the situation, you might want to combine some of the other different structure types (which we don't cover so much here), build up three- or four-level structures, and so on. Be warned, though: with every additional layer, your program becomes more and more complicated. This makes it harder for you to keep track of what you're dealing with while you're writing it, harder to read when you or someone else comes back to the program at a later date, and more difficult to identify and correct mistakes in the code itself."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Summary"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* The elements of data types like lists or dictionaries can themselves be things like lists or tuples or dictionaries, allowing arbitrarily complex data structures to be built up.\n",
    "* `for` loops can be nested in order to access every entry in these complex structures.\n",
    "* Individual entries can be accessed by stacking up indices/keys, which Python interprets one at a time, from left to right.\n",
    "* The values of variables can be inserted into strings, with their format controlled, using the `.format()` string method."
   ]
634 635 636 637 638
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
639
    "#### _Debugging Exercise_"
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this exercise, you are presented with some code that doesn't work as it should. Your task is to debug it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
657 658
    "# You start with a group of students and scores and you \n",
    "# would like to print the name and the score of each.\n",
659 660 661 662 663 664 665 666
    "# Can you spot and fix the errors?\n",
    "# Hint: Each line contains at least one error/mistake\n",
    "\n",
    "group = '{Sarah:20, Richard:30, Matthew:40, Fiona:50, Sally:60, Samuel:70}'\n",
    "\n",
    "for student in group_of_students:\n",
    "    print(\"The score of {} is {}\".format(student, group(student))\n"
   ]
667 668 669 670
  }
 ],
 "metadata": {
  "kernelspec": {
671
   "display_name": "Python 3",
672
   "language": "python",
673
   "name": "python3"
674 675 676 677
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
678
    "version": 3
679 680 681 682 683
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
684
   "pygments_lexer": "ipython3",
685
   "version": "3.5.2"
686 687 688 689 690
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}