Removing Duplicates
What You Will Learn in This Lesson
By the end of this lesson, you will be able to:
- Remove exact repeats while keeping the original order.
- Normalise text with
stripandlowerso the same value is recognised. - Keep the first spelling of each value while comparing a normalised key.
- Deduplicate whole records on the fields that identify them.
Why This Matters
A student entered twice is counted twice, in every count and every average, and nothing warns you. Removing duplicates is easy; the real work is deciding what “the same” means — the same name in a different case, the same person with a different score — and that decision is the one pandas’ drop_duplicates(subset=...) will ask you to make explicitly in unit 6.
Step 1: Exact duplicates
Start with the easy case: values that are character-for-character identical.
set() removes repeats and the order
A set keeps one of each value, which answers “how many distinct?” instantly. It has no order, so it is the wrong tool when the order of the rows means something.
names = ["Grace", "Ada", "Grace", "Alan"]
print(len(names), "rows,", len(set(names)), "distinct")
print(set(names))
A seen-set keeps the order
Walk the list, remember what you have already kept, and keep a value only the first time. The set is for fast membership tests; the list is the result.
names = ["Grace", "Ada", "Grace", "Alan"]
seen = set()
unique = []
for n in names:
if n not in seen:
seen.add(n)
unique.append(n)
print(unique)
Mini Practice #1: Two ways to count
Try It YourselfPrint how many distinct cities there are with set, then print the distinct cities in their original order.
Step 2: Same value, written differently
“Ada”, “ada” and “ Ada ” are one person to a human and three strings to Python.
Normalise to compare
strip() removes surrounding spaces and lower() removes case. The normalised form is a key for deciding sameness.
names = ["Ada", "ada", " Ada ", "GRACE"]
keys = [n.strip().lower() for n in names]
print(keys)
print(len(set(keys)), "people")
Compare the key, keep the original
The output should still say "Ada", not "ada". Use the key for the seen-set and append the original text.
names = ["Ada", " ada ", "Grace", "GRACE"]
seen = set()
kept = []
for n in names:
key = n.strip().lower()
if key not in seen:
seen.add(key)
kept.append(n)
print(kept)
Mini Practice #2: Messy subjects
Try It YourselfCount the subjects as a human would, ignoring case and spaces.
Step 3: Duplicate records
For whole rows, decide which fields identify a record. Two rows can share a name and be different people, or differ in a score and be the same entry typed twice.
A tuple of fields as the key
Dictionaries cannot go in a set, but a tuple of their identifying values can. Choose the fields that define “the same record” — here, name and date.
rows = [
{"name": "Ada", "date": "2024-01-05", "score": 92},
{"name": "Ada", "date": "2024-01-05", "score": 92},
{"name": "Ada", "date": "2024-02-01", "score": 95},
]
seen = set()
unique = []
for r in rows:
key = (r["name"], r["date"])
if key not in seen:
seen.add(key)
unique.append(r)
print(len(rows), "->", len(unique))
Report what you removed
The number of duplicates removed is part of the result. A few is housekeeping; a third of the file means something upstream is wrong.
names = ["Ada", "Grace", "Ada", "Ada"]
unique = list(dict.fromkeys(names))
print("removed", len(names) - len(unique), "duplicates of", len(names), "rows")
Key idea: dict.fromkeys(values) is a one-line order-keeping deduplication for exact matches — dictionary keys are unique and keep insertion order. It cannot normalise, so the loop is still the tool when case and spaces matter.
Step 4: When to Use It
Files that were appended to
Exports run twice, forms submitted twice. Deduplicate on the fields that identify a record.
key = (r["name"], r["date"])
Text typed by people
Normalise case and spaces to see that “Ada” and “ ada ” are one value, while keeping the original spelling.
When Not to Use It
Do not deduplicate on every field when two real records can share them, and do not use set() when order matters. Decide what “the same” means first.
End-of-Lesson Exercises
Exercise 1: Unique names, first spelling kept
Write unique_names(names) that returns the names with duplicates removed, ignoring case and surrounding spaces, keeping the first spelling of each and the original order.
Two things at once: a normalised key for deciding sameness, and the original text for the output. Keep a set of keys you have already seen.
Exercise 2: Duplicate records by key
Write dedupe(rows, fields) that returns a new list of the rows (dictionaries) with repeats removed, where two rows are the same if they agree on every field named in fields. Keep the first of each and the original order.
For each row build key = tuple(row[f] for f in fields). Keep the row only if key is not already in a seen set, then add it.