from typing import Iterator def generate_blocking_keys(record: dict) -> Iterator[tuple[str, str]]: """Yields (key_type, key_value) pairs for a company record.""" name = record.get("name", "") normalized = normalize_name(name) if normalized: yield ("name_norm", normalized) entity_type = record.get("entity_type", "") jurisdiction = record.get("jurisdiction_code", "") if entity_type and jurisdiction: yield ("type_jurisdiction", f"{entity_type}_{jurisdiction}") romanized = romanize(name) if romanized: phonetic = soundex(romanized) yield ("phonetic", phonetic) reg_num = record.get("registration_number", "") if reg_num: yield ("reg_prefix", reg_num[:6]) def build_candidate_pairs(records: list[dict]) -> set[tuple[int, int]]: """Return all candidate pairs sharing at least one blocking key.""" key_to_records: dict[tuple, list[int]] = {} for idx, record in enumerate(records): for key_type, key_value in generate_blocking_keys(record): bucket = (key_type, key_value) key_to_records.setdefault(bucket, []).append(idx) candidates: set[tuple[int, int]] = set() for indices in key_to_records.values(): for i in range(len(indices)): for j in range(i + 1, len(indices)): a, b = sorted([indices[i], indices[j]]) candidates.add((a, b)) return candidates