Build an inverse index from tags with defaultdict

An inverse index reverses a familiar relationship. Rather than asking which tags belong to item-17, it lets callers ask which item IDs have the sale tag. defaultdict(list) fits the construction loop because a missing tag automatically receives a fresh empty list when by_tag[tag] is read during append().

Each input row in this example is an item ID and a tuple of tag strings. The nested loop appends that ID under every tag it contains. Consequently, by_tag["sale"] becomes ['item-17', 'item-23'], preserving the input encounter order. The assertions check both that shared tags group multiple IDs and that a tag occurring once remains a one-element list.

A defaultdict changes on missing [] access: writing by_tag["archived"] would create and store an empty list. For a read-only lookup that must not alter the index, use by_tag.get("archived"), as shown. This recipe retains duplicate IDs if an input row repeats the same tag; normalize tags or use defaultdict(set) when uniqueness matters. Tags must also be hashable, and the index does not update itself if the original item-to-tags records later change.

This draft used AI assistance.

Source: Python defaultdict documentation

Example

from collections import defaultdict

items = [
    ("item-17", ("red", "sale")),
    ("item-23", ("sale", "small")),
    ("item-31", ("red",)),
]

by_tag = defaultdict(list)
for item_id, tags in items:
    for tag in tags:
        by_tag[tag].append(item_id)

assert by_tag["sale"] == ["item-17", "item-23"]
assert by_tag["small"] == ["item-23"]
assert "archived" not in by_tag

missing = by_tag.get("archived")
assert missing is None
assert "archived" not in by_tag

print(f"sale: {by_tag['sale']}")
print(f"red: {by_tag['red']}")
print(f"archived: {missing}")

Expected stdout

sale: ['item-17', 'item-23']
red: ['item-17', 'item-31']
archived: None

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic