TutorChase logo
Login
AQA A-Level Computer Science

11.7.4 Implementation and usage in programming

Dictionaries are powerful and efficient data structures used to store and retrieve values based on unique keys. This section explores their syntax, practical usage, handling missing keys, and performance benefits.

Creating dictionaries

Creating dictionaries in Python

In Python, dictionaries are defined using curly braces {}, where each key is paired with a corresponding value using a colon :. A dictionary represents a mapping between unique keys and associated values.

python

# Creating an empty dictionary
student_scores = {}

# Creating a dictionary with key-value pairs
student_scores = {'Alice': 92, 'Bob': 85, 'Charlie': 78}

Key points:

  • Keys must be unique within a dictionary.

  • Keys are typically of immutable types like strings, integers, or tuples.

  • Values can be of any type and do not need to be unique.

This makes dictionaries suitable for representing structured information like student records, user settings, or configuration data.

Creating dictionaries in Java

Java does not have a built-in dictionary type like Python but uses the Map interface, most commonly through HashMap from the Java Collections Framework.

java

import java.util.HashMap;

HashMap<String, Integer> studentScores = new HashMap<>();

studentScores.put("Alice", 92);
studentScores.put("Bob", 85);
studentScores.put("Charlie", 78);

Notes:

  • The put(key, value) method adds or updates entries.

Take your grades to the next level!

UPGRADING TO PREMIUM UNLOCKS
AI Tutor
AI-powered study assistant
instant feedback and guidance
Predicted Papers
Examiner-style predicted papers
based on recent exam trends
Practice Questions
All exam practice questions
by topic for each subject
Study Notes
All detailed revision notes
written by expert teachers
Cheat Sheets
Quick revision summaries
perfect for last-minute review
Past Papers
Complete collection
of practice and past exam papers
Email
Password
Confirm Password
Already have an account?

Practice Questions

FAQ

When a new key-value pair is added to a dictionary, the dictionary’s internal hash table calculates the hash code of the key using a built-in hash function. This hash code is then mapped to a specific index in an internal array where the key-value pair will be stored. If the calculated index is empty, the pair is stored immediately. However, if another item already occupies that index (a collision), the dictionary uses a collision resolution strategy such as chaining (storing multiple items at the same index using linked lists) or open addressing (finding the next available slot). Additionally, when the number of stored items exceeds a certain threshold (based on the load factor), the dictionary may automatically resize. Resizing involves creating a larger internal array and rehashing all existing key-value pairs into this new array. Although resizing is costly, it ensures that operations remain efficient and generally maintains average constant-time complexity.

In Python, only immutable data types can be used as dictionary keys because the key must have a fixed hash value that does not change during its lifetime in the dictionary. Immutable types include strings, integers, floats, and tuples (only if all elements inside the tuple are also immutable). These types can be reliably hashed and compared, which is essential for maintaining consistency in key lookups. If a mutable type such as a list or a dictionary is used as a key, Python will raise a TypeError, since these objects can change over time, potentially altering their hash values and breaking the integrity of the hash table. This restriction ensures that once a key is inserted, it remains stable and the dictionary can always locate it efficiently. It also prevents issues where a key’s value might be modified after insertion, leading to unexpected behaviour or loss of access to the associated data.

As of Python 3.7 and officially guaranteed from Python 3.8 onwards, dictionaries preserve the insertion order of items. This means that when iterating through a dictionary, items will appear in the order they were added. This behaviour is implemented by combining the hash table mechanism with a doubly linked list that maintains the sequence of insertions. While this adds some complexity to the internal structure, the performance of dictionary operations remains efficient, with average-case time complexity of O(1) for insertions, lookups, and deletions. The preservation of order is particularly useful for applications involving ordered data presentation, like serialisation to JSON or formatting reports. Despite the added functionality, Python’s optimised implementation ensures that performance overhead is minimal for most typical use cases. However, users should still avoid relying on insertion order for logic unless it is specifically required, as that was not the original purpose of dictionaries.

A dictionary can contain other dictionaries as values, but not as keys. This is because dictionaries are mutable, and mutable types cannot be used as keys since they are not hashable. Attempting to use a dictionary as a key will raise a TypeError. However, storing dictionaries as values is perfectly valid and often used to represent structured or hierarchical data. For example, a dictionary of student records may use student names as keys, with another dictionary as the value to store details such as age, grade, and ID. This structure is known as a nested dictionary. When working with nested dictionaries, care must be taken to check the existence of both top-level and nested keys to avoid KeyError exceptions. Nested dictionaries can become complex, so it's useful to use helper methods or loops to access deeply nested information. Their flexibility makes them ideal for JSON-like data structures or settings configurations in software systems.

Deleting many keys from a large dictionary does reduce the number of stored items, but the memory footprint of the dictionary may not decrease immediately. This is because Python dictionaries manage memory by maintaining a fixed-size internal array that only resizes downward in specific cases. The dictionary will not automatically shrink unless a rehash is triggered, which usually happens when a large number of deletions are followed by many insertions. Even after deletions, the allocated memory may remain reserved to allow for future additions without resizing. This design choice favours performance by reducing the frequency of costly resizing operations. However, if memory usage is a concern and the dictionary has been heavily modified, developers can force a size reduction by recreating the dictionary: copying remaining key-value pairs into a new dictionary. This approach discards the unused memory and ensures a tighter memory profile, but may introduce overhead if performed too frequently.

Hire a tutor

Please fill out the form and we'll find a tutor for you.

1/2
Your details
Alternatively contact us via
WhatsApp, Phone Call, or Email