Selecting and Filtering
Filter with Multiple Conditions
Combine two per-row boolean tests with Python's and in a loop to build a
single mask, then keep matching rows. With pandas, element-wise & combines
two boolean Series before indexing the DataFrame — and and or are not
valid for Series and will raise an error.
By hand
Loop over records, apply both conditions with and, and append the combined
bool to mask. Loop over indices to collect names where mask[i] is True.
naive.py
Replay: real traced execution (multi-file project)
# trace: ignore records
records = [
{'name': 'al', 'age': 20, 'score': 55},
{'name': 'bo', 'age': 25, 'score': 82},
{'name': 'cy', 'age': 22, 'score': 71},
{'name': 'di', 'age': 28, 'score': 90},
]
lo, hi = 21, 88
mask = []
for r in records:
mask.append(r['age'] > lo and r['score'] < hi)
names = []
for i in range(len(records)):
if mask[i]:
names.append(records[i]['name'])
print('RESULT:', names)
{'name': 'al', 'age': 20, 'score': 55},
2records = [3 {'name': 'al', 'age': 20, 'score': 55},4 {'name': 'bo', 'age': 25, 'score': 82},{'name': 'bo', 'age': 25, 'score': 82},
3{'name': 'al', 'age': 20, 'score': 55},4{'name': 'bo', 'age': 25, 'score': 82},5{'name': 'cy', 'age': 22, 'score': 71},{'name': 'cy', 'age': 22, 'score': 71},
4{'name': 'bo', 'age': 25, 'score': 82},5{'name': 'cy', 'age': 22, 'score': 71},6{'name': 'di', 'age': 28, 'score': 90},{'name': 'di', 'age': 28, 'score': 90},
5 {'name': 'cy', 'age': 22, 'score': 71},6 {'name': 'di', 'age': 28, 'score': 90},7]records = [
1# trace: ignore records2records = [3 {'name': 'al', 'age': 20, 'score': 55},hi ← 88, lo ← 21
7]8lo, hi = 21, 889mask = []values this step88hi21lomask ← []
8lo, hi = 21, 889mask = []10for r in records:values this step[]maskr ← {'name': 'al', 'age': 20, 'score': 55}
9mask = []10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)values this step{'name': 'al', 'age': 20, 'score': 55}rmask ← [False]
10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)12names = []values this step[] → [False]maskr ← {'name': 'bo', 'age': 25, 'score': 82}
9mask = []10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)values this step{'name': 'al', 'age': 20, 'score': 55} → {'name': 'bo', 'age': 25, 'score': 82}rmask ← [False, True]
10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)12names = []values this step[False] → [False, True]maskr ← {'name': 'cy', 'age': 22, 'score': 71}
9mask = []10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)values this step{'name': 'bo', 'age': 25, 'score': 82} → {'name': 'cy', 'age': 22, 'score': 71}rmask ← [False, True, True]
10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)12names = []values this step[False, True] → [False, True, True]maskr ← {'name': 'di', 'age': 28, 'score': 90}
9mask = []10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)values this step{'name': 'cy', 'age': 22, 'score': 71} → {'name': 'di', 'age': 28, 'score': 90}rmask ← [False, True, True, False]
10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)12names = []values this step[False, True, True] → [False, True, True, False]maskfor r in records:
9mask = []10for r in records:11 mask.append(r['age'] > lo and r['score'] < hi)names ← []
11 mask.append(r['age'] > lo and r['score'] < hi)12names = []13for i in range(len(records)):values this step[]namesi ← 0
12names = []13for i in range(len(records)):14 if mask[i]:values this step0iif mask[i]:
13for i in range(len(records)):14 if mask[i]:15 names.append(records[i]['name'])i ← 1
12names = []13for i in range(len(records)):14 if mask[i]:values this step0 → 1iif mask[i]:
13for i in range(len(records)):14 if mask[i]:15 names.append(records[i]['name'])names ← ['bo']
14 if mask[i]:15 names.append(records[i]['name'])16print('RESULT:', names)values this step[] → ['bo']namesi ← 2
12names = []13for i in range(len(records)):14 if mask[i]:values this step1 → 2iif mask[i]:
13for i in range(len(records)):14 if mask[i]:15 names.append(records[i]['name'])names ← ['bo', 'cy']
14 if mask[i]:15 names.append(records[i]['name'])16print('RESULT:', names)values this step['bo'] → ['bo', 'cy']namesi ← 3
12names = []13for i in range(len(records)):14 if mask[i]:values this step2 → 3iif mask[i]:
13for i in range(len(records)):14 if mask[i]:15 names.append(records[i]['name'])for i in range(len(records)):
12names = []13for i in range(len(records)):14 if mask[i]:stdout ← RESULT: ['bo', 'cy']
15 names.append(records[i]['name'])16print('RESULT:', names)values this stepRESULT: ['bo', 'cy']stdout
With pandas
(df['age'] > lo) & (df['score'] < hi) combines two boolean Series
elementwise. Parentheses around each condition are required because & has
higher operator precedence than > and <.
library.py
import pandas as pd
from dalib.display import set_display
set_display()
records = [
{'name': 'al', 'age': 20, 'score': 55},
{'name': 'bo', 'age': 25, 'score': 82},
{'name': 'cy', 'age': 22, 'score': 71},
{'name': 'di', 'age': 28, 'score': 90},
]
lo, hi = 21, 88
df = pd.DataFrame(records)
mask = (df['age'] > lo) & (df['score'] < hi)
filtered = df[mask]
print('mask:', mask.tolist())
print('names:', filtered['name'].tolist())
print('shape:', filtered.shape)
print('RESULT:', filtered['name'].tolist())
mask: [False, True, True, False]
names: ['bo', 'cy']
shape: (2, 3)
RESULT: ['bo', 'cy']
Implementation notes
- Use
&(bitwise AND) and|(bitwise OR) to combine boolean Series — NOT Python'sand/or.and/orcallbool()on the whole Series, which raisesValueError: The truth value of a Series is ambiguous. - Parentheses around each condition are mandatory:
(df['a'] > lo) & (df['b'] < hi). Without them,&binds tighter than>and the expression parses incorrectly. - This is the same operator rule as NumPy:
(a > lo) & (a < hi)— seecombine-two-masks(python-numpy ch06). - For more than two conditions, chain
&or|:(c1) & (c2) & (c3). Alternatively,df.query("age > 21 and score < 88")allows Python-styleand/orsyntax inside a string.