如何检查类/JSON对象所有属性是否为nil并高效过滤全nil对象?
高效过滤全属性为nil的Api::User对象
嘿,这个场景我之前处理过,完全不用挨个遍历每个对象的所有属性来检查,有几个资源消耗更低的方案,核心是利用短路求值——只要找到一个非nil的属性就停止检查,不用遍历完所有属性:
方案1:如果Api::User是ActiveRecord模型
ActiveRecord模型自带attributes方法,能直接拿到所有数据库字段的键值对。我们可以用none?来判断是否所有值都是nil(none?会在找到第一个非nil值时立刻返回false,比all?(&:nil?)更高效):
# 过滤掉全属性为nil的用户 filtered_users = users.reject { |user| user.attributes.values.none? }
方案2:如果Api::User是普通PORO(非ActiveRecord)
Ruby内置了instance_values方法,能获取对象所有实例变量的键值对。你可以给模型加一个复用性强的实例方法,或者直接在过滤时使用:
方式A:添加实例方法(推荐,便于维护)
class Api::User def all_attributes_nil? # none? 短路求值,找到第一个非nil值就停止 instance_values.values.none? end end # 过滤时直接调用方法 filtered_users = users.reject(&:all_attributes_nil?)
方式B:直接在过滤逻辑中使用
filtered_users = users.reject { |user| user.instance_values.values.none? }
方案3:在JSON转换阶段处理
如果不想提前过滤对象数组,也可以在生成JSON的时候直接跳过全nil的对象。比如用Jbuilder或者直接调用to_json前过滤:
# 用Jbuilder的例子 json.array! users.reject { |user| user.instance_values.values.none? } do |user| json.user_id user.user_id json.height user.height json.age user.age end # 直接转JSON的例子 users.reject { |user| user.instance_values.values.none? }.to_json
额外说明
- 如果你的模型有默认非nil的属性(比如某些字段默认是
0或空字符串),可以调整判断条件为:instance_values.values.all? { |v| v.nil? || v.blank? } - 这些方法的效率优势在于短路求值:比如一个对象有10个属性,只要第一个属性非nil,就不会再检查剩下的9个,比遍历所有属性的方式节省很多资源。
内容的提问来源于stack exchange,提问作者p4ndepravity
相关产品推荐
相关产品推荐

