Python 3 gradebook Step 3 and 4

https://www.codecademy.com/courses/learn-python-3/projects/python-gradebook
On Python 3 gradebook Step 3 says " Create a two-dimensional list to combine subjects and grades . Use the table below as a reference to associated values." and step 4 says my output should look like

[['physics', 98], ['calculus', 97], ['poetry', 85], ['history', 88]]

Do I manually type

gradebook = [['physics', 98], ['calculus', 97], ['poetry', 85], ['history', 88]]

or am I supposed to combine the two lists into a 2D list somehow?

Currently my code looks like this:

last_semester_gradebook = [["politics", 80], ["latin", 96], ["dance", 97], ["architecture", 65]]

# Your code below: 
subjects = ["physics", "calculus", "poetry", "history"]
grades = [98, 97, 85, 88]
gradebook = [subjects,grades]
print(gradebook)

and I know that the line

gradebook = [subjects,grades]

is wrong.

Before I delve into the lesson (thank you for the link, btw) let’s explore the question of how two lists can be paired up. In the above example, subjects could be interpreted as column headings in a spread sheet, and grades would be the data in each of the columns, albeit only the first row.

That brings us to this,

gradebook = [subjects,grades]

Examine this closely. What do we have?

[ ["physics", "calculus", "poetry", "history"], [98, 97, 85, 88] ]

Only, we know the two lists are connected so how do we merge them?

subjects = ["physics", "calculus", "poetry", "history"]
grades = [98, 97, 85, 88]
gradebook = [subjects, grades]
print (gradebook)
a, b = gradebook
print([[x, b[a.index(x)]] for x in a])
[['physics', 'calculus', 'poetry', 'history'], [98, 97, 85, 88]]
[['physics', 98], ['calculus', 97], ['poetry', 85], ['history', 88]]

Above, we know that x is always unique in a so the index is not a problem.

Mind, what is the gradebook variable going to be used for, later? If it has no lasting purpose then,

a, b = subjects, grades

I do this for simplicity. We know what a and b are and don’t have to type so much, or read as much. The picture is plain.

You can combine the two list like so:


subjects = ["physics", "calculus", "poetry", "history"]
grades = [98, 97, 85, 88]

gradebook = [[grades, subject] for (grades, subject) in zip(grades, subjects)]

This should give you the result you are looking for.

Thank you for both of your replies. Thus far in the class we have not learned to do either of these. Strange to me they would phrase it as though I am supposed to know how to zip these together.

1 Like

For this step they’re just having you get familiar with the idea. Typing it out manually is an acceptable answer, as is anything you might decide to research yourself. If you look at the hint, it just talks about the structure of a 2d list rather than method or list comprehensions.

Had a couple of over thought and buggy examples yesterday, so removed them. Today I’ve given it more thought and came up with this algorithm to merge the data at index [x] with the data at index [len(subjects)]. Turns out it is remarkably simple.

subjects = ["physics", "calculus", "poetry", "history"]
grades = [98, 97, 85, 88]
n = len(subjects)
c = subjects + grades
print (c)
['physics', 'calculus', 'poetry', 'history', 98, 97, 85, 88]
x = 0
while len(c) > n:
  c[x] = [c[x]] + [c.pop(n)]
  x += 1
  print (c)
[['physics', 98], 'calculus', 'poetry', 'history', 97, 85, 88]
[['physics', 98], ['calculus', 97], 'poetry', 'history', 85, 88]
[['physics', 98], ['calculus', 97], ['poetry', 85], 'history', 88]
[['physics', 98], ['calculus', 97], ['poetry', 85], ['history', 88]]

The key operation here is to turn the value at index [x] into a list then extend it with the value popped from index [n], also as a list.

We could also look at appending the popped value with basic recasting.

  c[x] = [c[x]]
  c[x].append(c.pop(n))

And since all the above is spaghetti code (inline), we can abstract it to a function with less verbosity and a direct return.

def pair(a, b):
  n = len(a)
  c = a + b
  x = 0
  while len(c) > n:
    c[x] = [c[x]]
    c[x].append(c.pop(n))
    x += 1
  return c

grade_book = pair(subjects, grades)
print (grade_book)
[['physics', 98], ['calculus', 97], ['poetry', 85], ['history', 88]]

This gives us a pseudo zip object but without the iterator. It’s still a re-usable list, or rather list of lists to represent a, b pairs. The choice of data structure is ours. As tuple pairs they would be immutable, also a consideration for use case. Tuples are the least expensive primary data structure. The above allows mutation of all the values.

Note the slight change-up in the code for tuples…

def pair(a, b):
  n = len(a)
  c = a + b
  x = 0
  while len(c) > n:
    c[x] = (c[x], c.pop(n))
    x += 1
  return c

grade_book = pair(subjects, grades)
print (grade_book)
[('physics', 98), ('calculus', 97), ('poetry', 85), ('history', 88)]

The above only allows changes to the parent list, but not the tuples it contains.

Now that we mention it, the list version can follow suit…

def pair(a, b):
  n = len(a)
  c = a + b
  x = 0
  while len(c) > n:
    c[x] = [c[x], c.pop(n)]
    x += 1
  return c
[['physics', 98], ['calculus', 97], ['poetry', 85], ['history', 88]]

The above with basic error checking to be sure of the correct number of pair values…

def pair(a, b):
  n = len(a)
  c = a + b
  if len(c) != n << 1:
    raise ValueError
  x = 0
  while len(c) > n:
    c[x] = (c[x], c.pop(n))
    x += 1
  return c
[('phys', 98), ('calc', 97), ('poet', 85), ('hist', 88), ('math', 94)]

Note: A left shift is binary. Multiplying by 2 is floating point. This is a cheap and dirty way to keep your math in integers, rather than floats.

Note also, concerning bit shifting (part of the Bitwise curriculum which hopefully comes up at some point) a left shift is always times 2. A right shift however, is not divided by 2, but rather floor divided by 2 since there is no fractional component. 3 shift right gives 1. There is no 1-1/2.

So left shifting is definite, while right shifting means we need to pay closer attention. If we need a float, then use float math. If the floor divided integer is enough, then use bitwise logic, or other integer math.

When you get to this unit, you’re going to love it.

1 Like

I like playing with recursive calls

subjects = ["physics", "calculus", "poetry", "history"]
grades = [98, 97, 85, 88]
def list_merge(a, b):
  if len(a) == 1 and len(b) == 1:
    return [[a[0], b[0]]]
  if len(a) == 1 and len(b) > 1:
    return [[a[0], b[0]], b[1:]]
  if len(b) == 1 and len(a) > 1:
    return [[a[0], b[0]], a[1:]]
  return  [[a[0], b[0]]] + list_merge(a[1:], b[1:])

print(list_merge(subjects, grades))
1 Like