Approach: build a hashmap from key → list of original indices for the first array (to handle duplicates), then iterate the second array and pop an index for each record’s key. This is O(n + m) time and O(n) extra space.python
from collections import defaultdict, deque
from typing import List, Dict, Any, Optional
def map_subset_indices(all_records: List[Dict[str, Any]],
subset_records: List[Dict[str, Any]],
key_field: str) -> List[Optional[int]]:
"""
Returns list of indices into all_records for each element in subset_records.
If a key from subset_records is missing, returns None for that position.
Handles duplicates by assigning indices in encounter order.
"""
positions = defaultdict(deque) # key -> deque of indices
for i, rec in enumerate(all_records):
positions[rec[key_field]].append(i)
result = []
for rec in subset_records:
k = rec[key_field]
if positions[k]:
result.append(positions[k].popleft()) # assign next available original index
else:
result.append(None) # should not happen if subset guarantee holds
return result
Key points:- Using deque ensures O(1) pop from left, preserving original-order assignment for duplicates.- Time complexity: O(n + m) where n = len(all_records), m = len(subset_records).- Space complexity: O(n) for the hashmap.Behavior with duplicates:- If keys repeat in all_records and subset_records contains fewer/more repeats, this implementation assigns indices in first-appearance order. If subset has more occurrences than available in all_records, we return None (or raise an error) depending on desired strictness.Streaming / Spark for very large datasets:- Streaming: build a compact external index (e.g., RocksDB or Redis) keyed by record key mapping to a queue of positions; as you stream subset records, pop positions atomically. If the first dataset is too large to pre-index in memory, write key→list-of-offsets to persistent store during initial scan.- Spark (batch): load both datasets as DataFrames, keep original index by adding monotonically_increasing_id() to all_records, then join subset_records to all_records on key and collect the id. For duplicates, use a join with an order column and window function (row_number over partition by key) on both datasets then join on (key, row_number) to get stable one-to-one matching.- Consider partitioning by key to keep operations local and scalable; use broadcast join only if subset is small.