Подтвердить что ты не робот

Условный ключ/значение в рубиновом хеше

Есть ли хороший (однострочный) способ записи хэша в рубине с некоторой записью только там, если условие выполнено? Я думал о

{:a => 'a', :b => ('b' if condition)}

Но это оставляет :b == nil, если условие не выполняется. Я понимаю, что это можно сделать легко в двух строках или около того, но было бы намного лучше в одной строке (например, при передаче хеша функции).

Я пропустил (а) еще одну из потрясающих особенностей рубина здесь?;)

4b9b3361

Ответ 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(',')}}")

для более простых условий добавления