Условный ключ/значение в рубиновом хеше
Есть ли хороший (однострочный) способ записи хэша в рубине с некоторой записью только там, если условие выполнено? Я думал о
{:a => 'a', :b => ('b' if condition)}
Но это оставляет :b == nil
, если условие не выполняется. Я понимаю, что это можно сделать легко в двух строках или около того, но было бы намного лучше в одной строке (например, при передаче хеша функции).
Я пропустил (а) еще одну из потрясающих особенностей рубина здесь?;)
Ответы
Ответ 1
Сначала вы можете создать хэш с ключом = > nil, если условие не выполнено, а затем удалите те пары, где значение равно nil. Например:
{ :a => 'a', :b => ('b' if cond) }.delete_if{ |k,v| v.nil? }
дает, для cond == true:
{:b=>"b", :a=>"a"}
и для cond == false
{:a=>"a"}
UPDATE
Это эквивалентно - немного более кратким и в рубине 1.9.3 обозначение:
{ a: 'a', b: ('b' if cond) }.reject{ |k,v| v.nil? }
Ответ 2
Из Ruby 1.9+, если вы хотите построить хэш на основе условных выражений, вы можете использовать tap
, что является моей новой любимой вещью. Это разбивает его на несколько строк, но более читаемо ИМХО:
{}.tap do |my_hash|
my_hash[:a] = 'a'
my_hash[:b] = 'b' if condition
end
Ответ 3
Заинтересованы в получении других ответов, но это лучшее, что я могу придумать для одного лайнера (я тоже плохо знаю однострочники: P)
{:a => 'a'}.merge( condition ? {:b => 'b'} : {} )
Ответ 4
В Rails:
{a: 'asd', b: nil}.compact
=> {:a=>"asd"}
Ответ 5
Hash[:a, 'a', *([:b, 'b'] if condition1), *([:c, 'c'] if condition2)]
Это зависит от того, что *nil
расширяется до вакуума в ruby 1.9. В рубине 1.8 вам может понадобиться:
Hash[:a, 'a', *(condition1 ? [:b, 'b'] : []), *(condition2 ? [:c, 'c'] : [])]
или
Hash[:a, 'a', *([:b, 'b'] if condition1).to_a, *([:c, 'c'] if condition2).to_a]
Ответ 6
Здесь много умных решений, но IMO - самый простой и, следовательно, лучший подход -
hash = { a: 'a', b: 'b' }
hash[:c] = 'c' if condition
Это противоречит запросу OP сделать это в двух строках, но на самом деле так же делают и другие ответы, которые кажутся только однострочными. Давайте посмотрим правде в глаза, это самое тривиальное решение и легко читается.
Ответ 7
Если у вас есть несколько условий и логики, которые другие должны будут понять позже, я предлагаю, чтобы это не было хорошим кандидатом для 1 лайнера. Было бы разумнее правильно создать хэш на основе требуемой логики.
Ответ 8
Это хорошо для нескольких условных выражений.
(
hash = {:a => 'a'}.tap {|h|
h.store( *[(:b if condition_b), 'b'] )
h.store( *[(:c if condition_c), 'c'] )
}
).delete(nil)
Обратите внимание, что я выбрал нуль как ключ "мусор", который удаляется, когда вы закончите. Если вам когда-либо понадобится хранить реальное значение с помощью ключа nil, просто измените условия хранения на что-то вроде:
(condition_b ? :b : garbage_key)
затем удалите (garbage_key) в конце.
Это решение также сохранит существующие значения nil неповрежденными, например. если у вас было: a = > nil в исходном хеше, оно не будет удалено.
Ответ 9
В Ruby 2.0 для хэшей (и параметров ключевого слова) используется оператор double-splat (**
) по аналогии с старым оператором splat (*
) для массивов (и позиционных параметров). Поэтому вы можете сказать:
{a: 'b', **(condition ? {b: 'b'} : {})}
Ответ 10
hash, hash_new = {:a => ['a', true], :b => ['b', false]}, {}
hash.each_pair{|k,v| hash_new[k] = v[1] ? v : nil }
puts hash_new
Ответ 11
Мое однострочное решение:
{:a => 'a'}.tap { |h| h.merge!(:b => 'b') if condition }
Ответ 12
eval("{:a => 'a' #{', :b => \'b\'' if condition }}")
или даже
eval("{#{[":a => 'a'", (":b=>'b'" if ax)].compact.join(',')}}")
для более простых условий добавления