LambdaLabTM
Computer Science · Class 11 · Dictionary Revisited
DictionariesPrograms⏱️ 15 min read

Names, Salaries & Records

The syllabus's second named program: a dictionary of employees and their salaries, and the questions you would actually ask of one. It is the same handful of shapes as the tuple chapter — a total, a champion, a search, a filter — written against keys and values instead of rows.

1The dictionary, and why it is one

employees.py
# name -> salary

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

print(salary['Amit'])
print(len(salary))
Output
55000
4
Key Takeaway
The same data could be a tuple of rows. (('Riya', 42000), ('Amit', 55000), …) holds exactly the same facts. The dictionary earns its place on one question: what does Amit earn? The dictionary answers it in one step, salary['Amit']. The tuple has to be searched row by row. Whenever the data is naturally “look this up by name”, that is the signal for a dictionary.

2Program 1 — print the payroll

payroll.py
# every employee and what they earn

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

for name, pay in salary.items():
    print(name, '->', pay)
Output
Riya -> 42000
Amit -> 55000
Sara -> 38000
John -> 61000

With f-strings the columns can be made to line up, which matters the moment a report is more than four lines long:

payroll_neat.py
# widths, so the numbers line up on the right

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

for name, pay in salary.items():
    print(f'{name:<8}{pay:>8}')
Output
Riya       42000
Amit       55000
Sara       38000
John       61000

{name:<8} pads the name to eight characters on the left, and {pay:>8} pushes the number to the right of an eight-wide column.

3Program 2 — the total and the average

📋 The problem

Find the company's monthly salary bill and the average salary.

The names play no part in this answer, so this is the one place .values() is exactly right:

salary_bill.py
# only the numbers matter here

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}
total = 0

for pay in salary.values():
    total = total + pay

print('Total salary bill:', total)
print('Average salary:   ', total / len(salary))
Output
Total salary bill: 196000
Average salary:    49000.0

len(salary) counts the pairs — four employees — which is the number to divide by. And the built-in version is two lines:

salary_bill_builtin.py
salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

print(sum(salary.values()))
print(sum(salary.values()) / len(salary))
Output
196000
49000.0

4Program 3 — who is paid the most?

📋 The problem

Find the highest-paid employee, by name.

Now the name is part of the answer, so .values() is useless and it has to be .items(). Two champions again, moving together:

highest_paid.py
# the champion program, over key-value pairs

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

top_name = ''
top_pay = 0

for name, pay in salary.items():
    if pay > top_pay:
        top_pay = pay
        top_name = name

print('Highest paid:', top_name, '-', top_pay)
Output
Highest paid: John - 61000
top_pay = 0

Safe here, because a salary is never negative or zero. On data that can be negative — a profit-and-loss table — start from a real entry instead, as the tuple chapter did.

top_name = name

Inside the same if, so the pair never comes apart. Update the pay and forget the name and the program reports the right figure against the wrong person.

Tip
max(salary.values()) gives 61000 and not John. It hands back the biggest value with no idea which key it came from — which is the same limitation as max() on a tuple. The moment the answer has to name something, you are back to the loop.

5Program 4 — a lookup that does not crash

📋 The problem

Print what one named employee earns, or say they are not on the payroll.

A missing key is not a polite None — it stops the program:

lookup_crash.py
salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

print(salary['Kabir'])
Output
Traceback (most recent call last):
  File "lookup_crash.py", line 3, in <module>
    print(salary['Kabir'])
          ~~~~~~^^^^^^^^^
KeyError: 'Kabir'

There are two ways round it, and both are worth having. Ask first:

lookup_in.py
# check the key exists before reaching for it

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}
wanted = 'Sara'

if wanted in salary:
    print(wanted, 'earns', salary[wanted])
else:
    print(wanted, 'is not on the payroll')
Output
Sara earns 38000
the same program with wanted = 'Kabir'
Output
Kabir is not on the payroll

Or hand get() something to say instead:

lookup_get.py
salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

print(salary.get('Kabir', 'not on the payroll'))
Output
not on the payroll
Key Takeaway
in when the two cases need different sentences; get() when a stand-in value will do. get() shines when the fallback is a number that keeps the arithmetic working — salary.get(name, 0) lets a total carry on past an unknown employee instead of stopping.

6Program 5 — everyone earning above a figure

above.py
# a filter and a counter in one walk

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}
limit = 50000
count = 0

for name, pay in salary.items():
    if pay > limit:
        print(name, 'earns', pay)
        count = count + 1

print(count, 'employees earn more than', limit)
Output
Amit earns 55000
John earns 61000
2 employees earn more than 50000

The printing happens inside the loop because there is one line per matching employee. The count is printed after it, because there is one of those for the whole payroll — the same rule as the search page, in a smaller form.

7Program 6 — give everyone a 10% raise

A dictionary can be changed while you walk it — unlike a tuple — as long as you only change the values:

raise.py
# 10% more for everyone

salary = {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}

print('Before:', salary)

for name in salary:
    salary[name] = salary[name] + salary[name] * 10 // 100

print('After: ', salary)
Output
Before: {'Riya': 42000, 'Amit': 55000, 'Sara': 38000, 'John': 61000}
After:  {'Riya': 46200, 'Amit': 60500, 'Sara': 41800, 'John': 67100}
Watch Out
Writing back needs the key, so this loop cannot be .values() or .items(). Inside for name, pay in salary.items():, the line pay = pay + … changes only the loop variable and leaves the dictionary exactly as it was — the same trap as for m in marks: m = m + 5 on a list. The assignment has to be salary[name] = ….
Watch Out
But you must not add or remove keys mid-loop. Changing a value is fine; changing how many pairs there are is not:
RuntimeError: dictionary changed size during iteration
If new keys are needed, collect them in a second dictionary during the walk and update() afterwards.
raise.py

8Program 7 — when one employee has more than one fact

A salary is one number. A real record has a department, a joining date, a grade. The value can be a dictionary of its own:

staff.py
# the value is itself a dictionary

staff = {
    'Riya': {'dept': 'Sales', 'salary': 42000},
    'Amit': {'dept': 'Tech', 'salary': 55000},
}

for name, info in staff.items():
    print(name, 'works in', info['dept'], 'and earns', info['salary'])
Output
Riya works in Sales and earns 42000
Amit works in Tech and earns 55000

info holds a whole inner dictionary each round, so info['dept'] reaches inside it — exactly the stacking that student[2][1] did on nested tuples. staff['Riya']['dept'] is the same thing written in one go.

9Recap

Use a dictionary when the question is 'look it up by name'

salary['Amit'] is one step. The same data as a tuple of rows would have to be searched.

.values() for totals, .items() for anything that names something

max(salary.values()) gives 61000 and cannot tell you it was John's.

A missing key is a KeyError, not a None

Guard with `if name in salary:` or use salary.get(name, fallback).

Change values mid-loop, never the number of keys

salary[name] = … is fine. Adding or deleting a key raises RuntimeError: dictionary changed size during iteration.

✍️ Now write these yourself
  1. 1

    Find the lowest-paid employee by name.

    Hint · Program 3 with <, and a starting top_pay that no real salary can beat — or start from a real entry.

  2. 2

    Print everyone whose name starts with ‘S’.

    Hint · The keys are enough for the test, so for name in salary: works — with salary[name] if you want to print the figure too.

  3. 3

    Give a raise only to those earning below the average.

    Hint · Two passes: work the average out first, then walk the keys and write back with salary[name] = ….

  4. 4

    Ask for a name with input() and print that person's salary, or a polite message.

    Hint · Program 4. Names are case-sensitive as keys, so decide whether 'riya' should count.

  5. 5

    From the staff dictionary, print the total salary per department.

    Hint · A second dictionary keyed by department, filled with totals[d] = totals.get(d, 0) + info['salary'].

Quick Check

Why does the highest-paid program need .items() rather than .values()?

Quick Check

What happens to the dictionary in `for name, pay in salary.items(): pay = pay + 1000`?

Quick Check

Which of these is not allowed while looping over a dictionary?