ruby 2.1.1
有没有办法以一行或更简洁的方式完成这段代码中的逻辑?
user = User.new
h = Hash.new
attrs = [:name, :foo, :bar]
attrs.each do |a|
h[a] = user[a] if user.has_attribute? a
end
return h
ruby 2.1.1
有没有办法以一行或更简洁的方式完成这段代码中的逻辑?
user = User.new
h = Hash.new
attrs = [:name, :foo, :bar]
attrs.each do |a|
h[a] = user[a] if user.has_attribute? a
end
return h
如果你使用 Rails 并且 User 是一个 ActiveRecord 模型(它看起来像你使用的has_attribute?
)那么这将做同样的事情:
user = User.new
...
return user.attributes.slice("name", "foo", "bar")
或者,如果你真的想要符号:
return user.attributes.with_indifferent_access.slice(:name, :foo, :bar)
看来您在 Rails 上。如果是这样,那么——
attrs = [:name, :foo, :bar]
# the result hash will be returned, if last line of the method.
user.attributes.extract!(*attrs)
看看这些方法extract!
和attributes
.
例子 :
arup@linux-wzza:~/Rails/app> rails c
Loading development environment (Rails 4.1.1)
2.0.0-p451 :001 > h = { a: 1, b: 2, c: 3, d: 4 }
=> {:a=>1, :b=>2, :c=>3, :d=>4}
2.0.0-p451 :002 > h.extract!(:a ,:b ,:x)
=> {:a=>1, :b=>2}
2.0.0-p451 :003 >
上面的答案在 Rails 范围内是正确的,我只是添加通用解决方案:
# assuming user[a] returns nil, if user have no a attribute
[:name, :foo, :bar].
map{|a| [attr, user[a]]}.
reject{|k, v| v.nil?}.
to_h
# assuming user[a] can raise if not user.has_attribute?(a)
[:name, :foo, :bar].
map{|a| [attr, user.has_attribute?(a) && user[a]]}.
reject{|k, v| !v}.
to_h
我已将它们格式化为 NOT 单行,但它们仍然是单语句 :)
基本上,诀窍是“发明正确的方法链来将一个序列转换为另一个”,并且需要知道所有可枚举的序列转换方法(map/select/reduce/reject/...),以及一种转换方法将键值对数组转换为散列(#to_h
在 Ruby 2.1.1 中是标准的)