Merging and Combining
Merge Left
Walk all left rows, looking up each key in a right-table index and filling
None when no match exists. With pandas, pd.merge(..., how='left') keeps
every left row and fills missing right-side values with NaN. The library half
converts NaN to None so the RESULT is comparable to the naive half.
By hand
With pandas
pd.merge(left, right, on='id', how='left') preserves all left rows.
The unmatched right value becomes NaN, which forces the score column from
int64 to float64 (visible in score dtype: and score raw:). The library
then normalizes NaN → None for a RESULT comparable to the naive half.
naive.py
left = [
{'id': 1, 'name': 'al'},
{'id': 2, 'name': 'bo'},
{'id': 3, 'name': 'cy'},
]
right = [
{'id': 1, 'score': 80},
{'id': 3, 'score': 70},
]
right_idx = {}
for r in right:
right_idx[r['id']] = r['score']
joined = []
for l in left:
score = right_idx.get(l['id'])
joined.append((l['name'], score))
print('RESULT:', joined)
library.py
import pandas as pd
import math
from dalib.display import set_display
set_display()
left = pd.DataFrame({'id': [1, 2, 3], 'name': ['al', 'bo', 'cy']})
right = pd.DataFrame({'id': [1, 3], 'score': [80, 70]})
merged = pd.merge(left, right, on='id', how='left')
scores = [int(s) if not math.isnan(s) else None for s in merged['score'].tolist()]
print('columns:', merged.columns.tolist())
print('score dtype:', merged['score'].dtype)
print('score raw:', merged['score'].tolist())
print('ids:', merged['id'].tolist())
print('names:', merged['name'].tolist())
print('scores:', scores)
print('RESULT:', list(zip(merged['name'].tolist(), scores)))
columns: ['id', 'name', 'score']
score dtype: float64
score raw: [80.0, nan, 70.0]
ids: [1, 2, 3]
names: ['al', 'bo', 'cy']
scores: [80, None, 70]
RESULT: [('al', 80), ('bo', None), ('cy', 70)]
Implementation notes
- NaN vs None: pandas fills missing join values with
NaN(a float), not PythonNone. Thescorecolumn's dtype becomesfloat64because integer columns cannot holdNaNnatively. The library half usesint(s) if not math.isnan(s) else Noneto convert to Python-native types and restore comparability with the naive RESULT. (Pandas ≥1.0Int64nullable integer type can holdpd.NA, but converting that is a separate pattern.) - A left join is the most common join in practice: it keeps the "primary" table whole and attaches optional enrichment from the right, making missing values explicit rather than silently dropping rows.
how='right'keeps all right rows;how='outer'keeps all rows from both sides, filling NaN on whichever side lacks a match.- Cross-reference:
left-join-with-missing(python-data-basics) for the pure-Python.get()-with-None version.