一、开篇:从序列中"筛选"出你需要的
数据处理中,过滤是最基本的操作之一:从一堆数据中选出符合条件的。python的filter()函数就是专门干这个的——它像一个筛子,只让满足条件的元素通过。
先看一个简单例子:
# 从1-10中筛选出偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 方法一:for循环
evens1 = []
for n in numbers:
if n % 2 == 0:
evens1.append(n)
# 方法二:列表推导式
evens2 = [n for n in numbers if n % 2 == 0]
# 方法三:filter()函数
evens3 = list(filter(lambda n: n % 2 == 0, numbers))
print(evens1) # [2, 4, 6, 8, 10]
print(evens2) # [2, 4, 6, 8, 10]
print(evens3) # [2, 4, 6, 8, 10]
filter()和map()一样,返回的是迭代器(惰性求值)。它的核心优势在于可以很方便地与map()、其他迭代器组合,构建数据处理流水线。
二、filter()的基本用法
2.1 语法和核心概念
# filter()的语法
# filter(function, iterable)
# function: 过滤函数,返回true保留元素,返回false丢弃元素
# iterable: 可迭代对象
# 返回值: filter对象(迭代器)
# 基本示例
def is_positive(n):
"""判断是否为正数"""
return n > 0
numbers = [-3, -1, 0, 2, 5, -4, 7]
positives = list(filter(is_positive, numbers))
print(positives) # [2, 5, 7]
# 使用lambda
positives2 = list(filter(lambda n: n > 0, numbers))
print(positives2) # [2, 5, 7]
# ⚠️ filter对象是迭代器——只能遍历一次
result = filter(is_positive, numbers)
print(list(result)) # [2, 5, 7]
print(list(result)) # [] 迭代器已耗尽
2.2 function为none的特殊行为
# 💡 当function=none时,filter()会过滤掉所有"假值"元素
# 假值:false, none, 0, 0.0, "", [], {}, (), set()
items = [0, 1, "", "hello", none, [], [1, 2], false, true, {}, {"a": 1}]
truthy = list(filter(none, items))
print(truthy)
# [1, 'hello', [1, 2], true, {'a': 1}]
# 实际应用:过滤掉空字符串
words = ["python", "", "java", " ", "rust", "", "go"]
# filter(none) 不会过滤 " "(空白字符也是非空字符串)
non_empty = list(filter(none, words))
print(non_empty) # ['python', 'java', ' ', 'rust', 'go']
# 如果要过滤纯空格字符串
non_blank = list(filter(lambda s: s.strip(), words))
print(non_blank) # ['python', 'java', 'rust', 'go']
# 💡 实际场景:清理用户输入中的无效选项
user_inputs = ["选项a", "", none, "选项b", " ", "选项c"]
valid_inputs = list(filter(lambda x: x and x.strip(), user_inputs))
print(valid_inputs) # ['选项a', '选项b', '选项c']
2.3 filter()配合内置方法和函数
# 使用str的方法作为过滤条件
words = ["python", "java", "rust", "go", "typescript", "c"]
# 筛选全小写的
lowercase_words = list(filter(str.islower, words))
print(lowercase_words) # ['java', 'typescript']
# 筛选全大写的
uppercase_words = list(filter(str.isupper, words))
print(uppercase_words) # ['go']
# 筛选以特定字符开头的
starts_with_p = list(filter(lambda s: s.lower().startswith("p"), words))
print(starts_with_p) # ['python']
# 筛选数字
mixed = ["abc", "123", "hello456", "789", "word"]
is_digit = list(filter(str.isdigit, mixed))
print(is_digit) # ['123', '789']
三、filter()的进阶用法
3.1 多个条件组合
data = [
{"name": "张三", "age": 28, "score": 85, "active": true},
{"name": "李四", "age": 22, "score": 92, "active": true},
{"name": "王五", "age": 35, "score": 78, "active": false},
{"name": "赵六", "age": 19, "score": 95, "active": true},
{"name": "钱七", "age": 30, "score": 65, "active": true},
]
# 多个条件(and关系):年龄大于20且分数大于80且活跃
qualified = list(filter(
lambda u: u["age"] > 20 and u["score"] > 80 and u["active"],
data
))
print([u["name"] for u in qualified]) # ['张三', '李四']
# 多个条件(or关系):年龄大于30或分数大于90
special = list(filter(
lambda u: u["age"] > 30 or u["score"] > 90,
data
))
print([u["name"] for u in special]) # ['李四', '王五', '赵六']
# 条件函数分离——提高可读性
def is_qualified(user):
"""判断用户是否合格"""
return (
user["age"] >= 20
and user["score"] >= 60
and user["active"]
)
def is_excellent(user):
"""判断用户是否优秀"""
return user["score"] >= 90
qualified_users = list(filter(is_qualified, data))
excellent_users = list(filter(is_excellent, qualified_users))
print([u["name"] for u in excellent_users]) # ['李四', '赵六']
3.2 filter()与map()的组合
# 💡 经典模式:先过滤(filter),再转换(map)
# 场景:从学生列表中筛选出高分学生,并格式化输出
students = [
{"name": "alice", "math": 85, "english": 92},
{"name": "bob", "math": 65, "english": 70},
{"name": "charlie", "math": 95, "english": 88},
{"name": "diana", "math": 72, "english": 90},
{"name": "eve", "math": 58, "english": 62},
]
# 流水线:筛选(总分>160) → 计算总分 → 格式化
# 方法一:filter + map
high_scorers = filter(lambda s: s["math"] + s["english"] > 160, students)
formatted = map(
lambda s: f"{s['name']}: {s['math'] + s['english']}分",
high_scorers
)
print(list(formatted)) # ['alice: 177分', 'charlie: 183分', 'diana: 162分']
# 方法二:列表推导式(一条龙)
result = [
f"{s['name']}: {s['math'] + s['english']}分"
for s in students
if s["math"] + s["english"] > 160
]
print(result) # 相同结果
# 💡 列表推导式在处理filter+map组合时通常更简洁
3.3 链式过滤
# 应用多个过滤条件,逐步筛选
# 场景:电影推荐系统
movies = [
{"title": "盗梦空间", "genre": "科幻", "rating": 9.3, "year": 2010},
{"title": "肖申克的救赎", "genre": "剧情", "rating": 9.7, "year": 1994},
{"title": "星际穿越", "genre": "科幻", "rating": 9.4, "year": 2014},
{"title": "霸王别姬", "genre": "剧情", "rating": 9.6, "year": 1993},
{"title": "阿凡达", "genre": "科幻", "rating": 8.7, "year": 2009},
{"title": "泰坦尼克号", "genre": "爱情", "rating": 9.4, "year": 1997},
{"title": "流浪地球", "genre": "科幻", "rating": 7.9, "year": 2019},
]
# 筛选条件:科幻片 + 评分>=9.0 + 2010年之后
def filter_genre(genre):
return lambda movie: movie["genre"] == genre
def filter_min_rating(rating):
return lambda movie: movie["rating"] >= rating
def filter_after_year(year):
return lambda movie: movie["year"] >= year
# 链式过滤
step1 = filter(filter_genre("科幻"), movies)
step2 = filter(filter_min_rating(9.0), step1)
step3 = filter(filter_after_year(2010), step2)
result = list(step3)
for movie in result:
print(f" {movie['title']} ({movie['year']}) - {movie['rating']}分")
# 星际穿越 (2014) - 9.4分
# 💡 或者用列表推导式一行搞定
result2 = [
m for m in movies
if m["genre"] == "科幻" and m["rating"] >= 9.0 and m["year"] >= 2010
]
四、itertools.filterfalse()
# filterfalse():与filter()相反——保留函数返回false的元素
from itertools import filterfalse
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# filter: 保留偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [0, 2, 4, 6, 8]
# filterfalse: 排除偶数(即保留奇数)
odds = list(filterfalse(lambda x: x % 2 == 0, numbers))
print(odds) # [1, 3, 5, 7, 9]
# 实际应用:过滤掉无效数据
data = ["valid1", "", "valid2", none, "valid3", " "]
# 排除空值和none
def is_invalid(value):
return value is none or (isinstance(value, str) and not value.strip())
valid_data = list(filterfalse(is_invalid, data))
print(valid_data) # ['valid1', 'valid2', 'valid3']
五、实战案例
5.1 数据清洗
# 场景:清洗从csv读取的数据
raw_data = [
["张三", "25", "zhangsan@email.com", "北京"],
["李四", "", "lisi@email.com", "上海"], # 年龄缺失
["", "30", "wangwu@email.com", "广州"], # 姓名缺失
["赵六", "28", "", "深圳"], # 邮箱缺失
["钱七", "35", "qianqi@email.com", ""], # 城市缺失
["孙八", "invalid", "sunba@email.com", "杭州"], # 年龄无效
]
def is_valid_row(row):
"""检查数据行是否完整有效"""
name, age_str, email, city = row
# 检查非空
if not all([name, age_str, email, city]):
return false
# 检查年龄是数字
try:
age = int(age_str)
if age <= 0 or age > 150:
return false
except valueerror:
return false
# 检查邮箱包含@
if "@" not in email:
return false
return true
# 过滤并转换
valid_data = filter(is_valid_row, raw_data)
cleaned = list(map(
lambda row: {
"name": row[0],
"age": int(row[1]),
"email": row[2],
"city": row[3],
},
valid_data
))
for record in cleaned:
print(record)
# {'name': '张三', 'age': 25, 'email': 'zhangsan@email.com', 'city': '北京'}
5.2 用户输入校验
# 场景:批量验证用户提交的注册信息
registrations = [
{"username": "alice", "email": "alice@test.com", "age": 25, "password": "abc12345"},
{"username": "bob", "email": "bob", "age": 30, "password": "12345678"}, # 邮箱格式不对
{"username": "charlie", "email": "charlie@test.com", "age": 17, "password": "pw"}, # 年龄和密码不符合
{"username": "d", "email": "diana@test.com", "age": 22, "password": "pass123"}, # 用户名太短
]
def validate_registration(reg):
"""验证注册信息"""
errors = []
if len(reg["username"]) < 3:
errors.append("用户名至少3个字符")
if "@" not in reg["email"] or "." not in reg["email"]:
errors.append("邮箱格式不正确")
if reg["age"] < 18:
errors.append("年龄必须≥18岁")
if len(reg["password"]) < 8:
errors.append("密码至少8个字符")
return len(errors) == 0, errors
# 筛选出验证失败的
invalid = list(filterfalse(lambda r: validate_registration(r)[0], registrations))
for r in invalid:
_, errors = validate_registration(r)
print(f"{r['username']}: {', '.join(errors)}")
# bob: 邮箱格式不正确
# charlie: 年龄必须≥18岁, 密码至少8个字符
# d: 用户名至少3个字符
六、总结
filter()是python数据处理的必备工具。它和map()、lambda一起,构成了python函数式编程的基础三件套。
核心要点:
filter(func, iterable)返回满足条件的元素组成的迭代器filter(none, iterable)过滤掉假值(0、“”、none、[]等)filterfalse(func, iterable)是filter的"反向"版本- 有复杂条件时,用命名的过滤函数代替lambda更清晰
- filter+map组合很适合做数据处理流水线
选型建议:
- filter+map的组合 → 列表推导式通常更简洁
- 使用内置函数作为过滤条件 →
filter(str.isdigit, data)很优雅 - 链式多层过滤 → 考虑用filterfalse排除法思路
- 大型数据集 → filter的惰性求值可以节省内存
到此这篇关于python中filter()函数实现按条件过滤序列元素详解的文章就介绍到这了,更多相关python filter()过滤内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论