FAQ: Survey of Computer Science - The Tale of Kenny - Kenny the Teacher

This community-built FAQ covers the “Kenny the Teacher” exercise from the lesson “Survey of Computer Science - The Tale of Kenny”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Code Foundations

FAQs on the exercise Kenny the Teacher

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

1 Like

What does the . Key() function do?

1 Like

Hi!
looking on code:
if (grades[student_a] > grades[student_b]) and (grades[student_a] > grades[top_of_class]):
_ top_of_class = student_a_
_ elif (grades[student_b] > grades[student_a]) and (grades[student_b] > grades[top_of_class]):_
_ top_of_class = student_b_

I was thinking "(grades[student_b] > grades[student_a]) " is there for situation when both grades are the same, but there is no else at the end. So why is this condition tested in elif?

We use elif when we wish to text another condition. Some situations do not have a default action so we leave off the else but we should not consider the above an either/or situation. If one condition is met, follow that branch, else if the next condition follow that branch. Given that neither condition is met, do nothing.

That would be the .keys() method of the dict class.

>>> obj = { 'one': 1, 'two': 2, 'three': 3, 'four': 4 }
>>> obj.keys()
dict_keys(['four', 'two', 'one', 'three'])
>>> 

As we see above, it returns a dict_keys object.

>>> for x in obj.keys():
	print (x, end=' ')

	
four two one three 
>>> 

Witness that neither object is actually ordered.

1 Like

top_of_class = list(grades.keys())[0]
i didn’t understood this from kenny’s algorithm

1 Like

Consider,

>>> obj = { 'one': 1, 'two': 2, 'three': 3, 'four': 4 }
>>> obj.keys()[0]
Traceback (most recent call last):
  File "<pyshell#46>", line 1, in <module>
    obj.keys()[0]
TypeError: 'dict_keys' object does not support indexing
>>> list(obj.keys())[0]
'two'
>>> 

Notice the dict_keys object is not subscriptable? Hence, the need to cast it as a list object before subscripting.

The value is not important since it is taken out of order, that is why we need to iterate over all the keys to find the highest value and assign it to top_of_class.

1 Like

Hey guys!
In the part ‘What are algorithms’ we were given instructions about an exercise.

The exercice was: identify what piece of code is associated with each step.

Here are the steps:

  1. Get list of unpaired students
  2. Create empty list of paired students
  3. Until the list of following students is empty, repeat the following steps:
    4. Determine the students with the highest grade in the unpaired list
    5. Determine the students with the lowest grade in the unpaired list
    6. Pair those students and add that list to the list of paired students
    7. Remove those students from the list of unpaired students
  4. Print the list of paired students to the terminal

Here are the answers that I managed to find. Are they right or wrong?
If ‘wrong’ it would be very interesting to know why there were wrong.

Answers:

  1. Get list of unpaired students

student_grades = {“Jeremy” : 87, “Kyla” : 82, “Ayesha” : 90, “Aleida” : 94, “Todd” : 79, “Maxwell” : 98, “Yolonda” : 81, “Kiyoko” : 71, “Dagmar” : 73, “Laura” : 91, “Shimeah” : 81, “Songqiao” : 92, “Frankie” : 87, “Natalia” : 95, “Gonzalo” : 82, “Pavel” : 78}

  1. Empty list of unpaired students

student_pairs =

  1. Determine students with highest grade in the unpaired list

def highest_grade(grades):
top_of_class = list(grades.keys())[0]

  1. Determine students with the lowest grade in the unpaired list

def lowest_grade(grades):
bottom_of_class = list(grades.keys())[0]

  1. Pair students and add that list to the list of paired students

student_pairs.append([highest_grade(grade_dict), lowest_grade(grade_dict)])

  1. Remove those students from the list of unpaired students

grade_dict.pop(highest_grade(grade_dict))
grade_dict.pop(lowest_grade(grade_dict))

  1. Print the list

print(student_pairs)

4 Likes

This is not the actual top_of_class (though it may be), just a starting point in the list. We still have to cycle through and compare and update that variable so the final return is indeed the top student/grade.

LIkewise with that as well. We need to load up a starting value (dictionary) that can be compared as we cycle through the data.

We can see that this demonstration would have taken a good long while to construct if we started from scratch and need instructions. The main idea here is that we see the working parts and understand their various roles and output data at each point.

3 Likes

Thank you for your answers!

I am a total beginner at coding but I am eager to learn and since it’s completely new to me I tried to apply my personal logic on this, but as every scientific fields it has its own logic that needs to be respected and applied.

But I understood the main idea behind this algorithm. In my imagination I saw this algorithm as a painting.

Can we compare coding to mathematics demonstration?

There are some parallels, but math is not programming and programming is not math. They are both unique languages with their own specialized purposes. Maths let us understand NUMBER concepts; programming lets us give instructions to a computer. Many operations in both disciplines involve algorithms and patterns, but that is where they diverge.

We can use a program to perform maths, provided we have written the appropriate expressions and algorithms, but it would be very hard to use maths to write a set of computer instructions. You see what I’m getting at?

2 Likes

In the code:

“top_of_class = list(grades.keys())[0]
for student_a in grades:
for student_b in grades:”

Can you explain the need for a nest loop here? Could we not just use the following:

“top_of_class = list(grades.keys())[0]
for student_a in grades:
if (grades[student_a] > grades[top_of_class]):
top_of_class = student_a”

and same for the bottom of the class?

2 Likes

I could, but then so can you, so I’ll save us both. Let’s perform our own test, to prove out your theory.

First add these two functions to the source code…

# test functions

def top_grade(grades):
  top_of_class = list(grades.keys())[0]
  for student_a in grades:
    if (grades[student_a] > grades[top_of_class]):
      top_of_class = student_a
  return top_of_class

def bottom_grade(grades):
  bottom_of_class = list(grades.keys())[0]
  for student_a in grades:
    if (grades[student_a] < grades[bottom_of_class]):
      bottom_of_class = student_a
  return bottom_of_class

and we’ll touch up Kenny’s Algorithm, slightly…

def kennys_algorithm(grade_dict):
  student_pairs = []
  test_pairs = []
  while len(grade_dict) > 0:
    student_pairs.append([highest_grade(grade_dict), lowest_grade(grade_dict)])
    test_pairs.append([top_grade(grade_dict), bottom_grade(grade_dict)])
    grade_dict.pop(highest_grade(grade_dict))
    grade_dict.pop(lowest_grade(grade_dict))
  print(student_pairs)
  print(test_pairs)
  print ([x for x in student_pairs if x not in test_pairs])
  print ([x for x in test_pairs if x not in student_pairs])

Now run it. We can see that at the end, both lists are empty, as we would expect since the output of the two lists appear identical on the screen.

Being as intuitive as you are, having found this scenario, can you walk it back to what the author has given us to study and find the answer to your first question? Would the lesson have made as much sense to a naive learner if it was presented like our test case? Or would the learner find it more difficult to grasp? Questions like these must perplex course creators every step of the way.

Hi mtf,

First of all I should clarify here, in my original question I meant if we used the following code
rather than a nested loop.

def highest_grade(grades):
top_of_class = list(grades.keys())[0]
for student_a in grades:
if (grades[student_a] > grades[top_of_class]):
top_of_class = student_a
return top_of_class

def lowest_grade(grades):
bottom_of_class = list(grades.keys())[0]
for student_b in grades:
if (grades[student_b] < grades[bottom_of_class]):
bottom_of_class = student_b

In using this code I was able to get back to the same results. So my real question was why was the nested code used as opposed to this simpler code. However after researching nested loops a bit more, it just seemed like it was just matter of preference.

Thanks for the encouragement! It ultimately pushed me to understand the subject matter a little more. I would say overall this question came about mostly because of my lack of nested loop knowledge, specifically the fact that a variable in the outer loop (student_a) was used and referenced in the inner loop for student_b. Overall it took some more research, with the help of this video here: _https://www.youtube.com/watch?v=shO5VbD2rNI_, to better understand what values are being compared to.

I see now that the use of coding method language to get to the same results is just a matter of preference.

1 Like

Note that in my example, both approaches are merged so they draw upon the exact same data in the loop. In real code, we would choose one approach or the other.

When it can be proven that both methods give the exact same results, every time, then preference may be a determining factor, but other factors come into play, as well.

1. readability
2. simplicity
3. efficiency (not a concern for a beginner)

There are an hundred ways to cook an egg. A Red Seal Chef knows them all, but then it is the circumstances and desired outcome that dictate which will be used in any particular instance. No egg cooking class starts with a soufflé. Boiling, poaching, frying, abd scrambling usually come first, followed by omelettes, then reaching the challenges.


Update

Here is the test code as a stand alone. We still need both, for the comparisons that are made at the end.

Dictionary
# This is a Python Dictionary that contains all of the students in Kenny's class as well as their grades.
student_grades = {"Jeremy" : 87, "Kyla" : 82, "Ayesha" : 90, "Aleida" : 94, "Todd" : 79, "Maxwell" : 98, "Yolonda" : 81, "Kiyoko" : 71, "Dagmar" : 73, "Laura" : 91, "Shimeah" : 81, "Songqiao" : 92, "Frankie" : 87, "Natalia" : 95, "Gonzalo" : 82, "Pavel" : 78}
Kenny's Algorithm
# This is a function that determines the student with the highest grade given a dictionary
def highest_grade(grades):
  top_of_class = list(grades.keys())[0]
  for student_a in grades:
    for student_b in grades:
      if (grades[student_a] > grades[student_b]) and (grades[student_a] > grades[top_of_class]):
        top_of_class = student_a
      elif (grades[student_b] > grades[student_a]) and (grades[student_b] > grades[top_of_class]):
        top_of_class = student_b
  return top_of_class

# This is a function that determines the student with the lowest grade given a dictionary
def lowest_grade(grades):
  bottom_of_class = list(grades.keys())[0]
  for student_a in grades:
    for student_b in grades:
      if (grades[student_a] < grades[student_b]) and (grades[student_a] < grades[bottom_of_class]):
        bottom_of_class = student_a
      elif (grades[student_b] < grades[student_a]) and (grades[student_b] < grades[bottom_of_class]):
        bottom_of_class = student_b
  return bottom_of_class

# This is Kenny's Algorithm! It sorts the students into pairs based on their grades.
def kennys_algorithm(grade_dict):
  student_pairs = []
  while len(grade_dict) > 0:
    student_pairs.append([highest_grade(grade_dict), lowest_grade(grade_dict)])
    grade_dict.pop(highest_grade(grade_dict))
    grade_dict.pop(lowest_grade(grade_dict))
  print(student_pairs)
  return student_pairs
Test Algorithm
# test functions
def top_grade(grades):
  top_of_class = list(grades.keys())[0]
  for student_a in grades:
    if (grades[student_a] > grades[top_of_class]):
      top_of_class = student_a
  return top_of_class

def bottom_grade(grades):
  bottom_of_class = list(grades.keys())[0]
  for student_a in grades:
    if (grades[student_a] < grades[bottom_of_class]):
      bottom_of_class = student_a
  return bottom_of_class

def test_algorithm(grade_dict):
  test_pairs = []
  while len(grade_dict) > 0:
    test_pairs.append([top_grade(grade_dict), bottom_grade(grade_dict)])
    grade_dict.pop(top_grade(grade_dict))
    grade_dict.pop(bottom_grade(grade_dict))
  print(test_pairs)
  return test_pairs

Run both and compare the outcomes…

student_pairs = kennys_algorithm(student_grades.copy())
test_pairs    = test_algorithm(student_grades.copy())

print ([x for x in student_pairs if x not in test_pairs])
print ([x for x in test_pairs if x not in student_pairs])
1 Like

noob here. my question is with the following code for kenny’s lists. The code to determine the student with the highest grade is similar to the code to determine the student with the lowest grade. how does the code know what is considered a high grade and a low grade???

This is a function that determines the student with the highest grade given a dictionary

def highest_grade(grades):
top_of_class = list(grades.keys())[0]
for student_a in grades:
for student_b in grades:
if (grades[student_a] > grades[student_b]) and (grades[student_a] > grades[top_of_class]):
top_of_class = student_a
elif (grades[student_b] > grades[student_a]) and (grades[student_b] > grades[top_of_class]):
top_of_class = student_b
return top_of_class

This is a function that determines the student with the lowest grade given a dictionary

def lowest_grade(grades):
bottom_of_class = list(grades.keys())[0]
for student_a in grades:
for student_b in grades:
if (grades[student_a] < grades[student_b]) and (grades[student_a] < grades[bottom_of_class]):
bottom_of_class = student_a
elif (grades[student_b] < grades[student_a]) and (grades[student_b] < grades[bottom_of_class]):
bottom_of_class = student_b
return bottom_of_class

The code doesn’t ‘know’, but it iterates through the grades and if a grade is higher than the one stored in top_of_class, it replaces that value with the new one. When iteration is complete, the highest grade of all will be stored there. Same thing applies to lowest grade.

hello, I was wondering if i could get help on a certain problem that i am stuck on

I am still a huge noob here but when the problem asks me to copy paste the algorithm into script.py i am a bit stuck as to what it’s asking me as there doesn’t seem to be anywhere to do it on the screen
sorry for any inconveniences

The script.py tab should be preloaded with the functions we need for this lesson. Is there nothing present in the editor?

there was nothing in the editor tab and i kept leaving and refreshing but i refreshed again and it is showing me the functions
thank you for your time

1 Like

Hey guys, I know this is made for simplicity and basic understanding but i’m curious as a beginner.

Given that this code is hypothetically written to make his life a little easier, i think he may have missed a step, or i will let my inexperience shine.

I was testing around the ideas in my head and wondered what the code would do if say certain people had higher or lower scores. So I changed todds grade to a 98, in doing this the program begins to pair people with themselves, ie if you give todd a 98 the end of the list becomes [‘Jeremy’, ‘Jeremy’] and for some reason by proxy frankies score of 87 becomes omitted and hes alone apparently.

What am I or the program missing that is causing these results to be skewed? In my head i imagine you should be able to enter any amount of variables with their own values and the program would be able still take x and pair it with y based on the given values.

I know this is an old exercise. I dont really expect a response but if any one does thank you for your time.