我如何检查类或json对象中的所有属性/值是否为零

时间:2018-05-16 18:38:09

标签: ruby-on-rails ruby elasticsearch

我有一个方法从API检索elasticsearch查询并将其转换为JSON对象数组。

在某些情况下,最后一个JSON对象不是nil对象,但所有属性都有nil值。

我想避免映射每个对象,但我需要过滤掉那些所有 nil值的JSON对象。

例如:

=> [#<Api::User:0x006546546
      @user_id=1,
      @height=70,
      @age=25>,
    #<Api::User:0x006546542
      @user_id=nil
      @height=nil
      @age=nil>]

我希望从数组中删除all-nil对象,无论是JSON格式还是将其转换为Api :: User对象数组。

地图是检查所有对象的所有值的唯一方法,还是资源密集度较低的方法?

4 个答案:

答案 0 :(得分:2)

我非常依赖EnumerableObject给你的方法。从Enumerable开始,我们可以使用select仅选择满足某些条件的数组元素。这个条件是至少有一个实例变量不是nil,为此我们可以使用any?

Object我们将使用instance_variables获取实例变量的集合,我们将使用instance_variable_get访问这些实例变量的值。

它看起来像这样:

filtered_array = array.select do |object| 
  object.instance_variables.any? { |var| object.instance_variable_get(var) }
end

当然any?是有效的,因为它将停止迭代并在第一个&#34; truthy&#34;上返回true。变量。正如SteveTurczyn建议的那样,如果你只需要检查最后一个值,那就更快了。

filtered_array = array[0..-2] if array[-1].instance_variables.none? { |var| object.instance_variable_get(var) }

答案 1 :(得分:1)

有人可能想出一个更好的方法,但似乎你不需要检查所有对象的所有值,因为你检查的第一个值是非零意味着对象是好的。我会做一些检查每个值的东西,直到找到非零值。如果您可以订购最有可能具有值的测试字段(例如user_id

,这也有助于提高效率
array.select do |object|
  %i(user_id height age).find do |field_name| 
    object.send(field_name)
  end
end

如果它只是需要测试的最后一个对象,那么更容易......

array.pop if %i(user_id height age).find {|field_name| array.last.send(field_name) }

答案 2 :(得分:1)

我确信有一种更清洁的方式,但万一你需要映射每个对象:

def are_attributes_not_nil?(my_object)
  my_object.instance_variables.map{ |attr| my_object.send(attr.to_s[1..-1]).nil? }.uniq.include? false
end
如果所有属性都是nil

,则

返回false

答案 3 :(得分:1)

我的解决方案涉及首先实现一种将对象转换为哈希值的方法,然后再将它们转换为JSON本身。

api_user_array #=> [#<Api::User:0x006546546 ... >, #<Api::User:0x006546542 ... >]
api_user_array = api_user_array.map(&:to_h).reject { |hash| hash.values.all?(&:nil?) }
# should result in an array of hashes with at least one value not nil

这假设您实现了 Api :: User#to_h 方法。这可能是这样的:

def attribute_names
  %w[user_id height age]
end

def to_h
  attribute_names.each_with_object({}) { |attr, hash| hash[attr] = send(attr) }
  # assuming all attributes have a getter, otherwise
  attribute_names.each_with_object({}) { |attr, hash| hash[attr] = instance_variable_get("@#{attr}") }
end