Массив в хэш с условной логикой в ​​Ruby?

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

3 ответа

Решение

Если вы используете 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

Я отформатировал их как НЕ с одним строком, но они все еще с одним утверждением:)

По сути, хитрость заключается в том, чтобы "придумать правильную цепочку методов для преобразования одной последовательности в другую", и она требует знания всех перечислимых методов преобразования последовательностей (map/select/ Reduce/ Reject/...), а также метода преобразования массив пар ключ-значение в хеш (#to_h стандартно в Ruby 2.1.1)

Другие вопросы по тегам