有条件的键/ruby散列值
有没有一个很好的(一行)的ruby写一个哈希与一些条目只有在条件满足? 我想到了
{:a => 'a', :b => ('b' if condition)}
但是,这留下:b == nil
如果条件不满足, :b == nil
。 我意识到这可以用两行左右的方式来完成,但是在一行中会更好(例如,当将散列传递给函数时)。
我还错过了另外一个ruby的惊人特征吗? ;)
当条件不满足时,您可以首先创buildkey => nil的散列,然后删除值为nil的那些对。 例如:
{ :a => 'a', :b => ('b' if cond) }.delete_if{ |k,v| v.nil? }
产量,为cond ==真实:
{:b=>"b", :a=>"a"}
并为cond == false
{:a=>"a"}
UPDATE
这是相当的 – 更简洁一点,在ruby1.9.3表示法:
{ a: 'a', b: ('b' if cond) }.reject{ |k,v| v.nil? }
从Ruby 1.9+开始,如果你想build立一个基于条件的散列,你可以使用tap
,这是我最喜欢的事情。 这打破了多行,但更具可读性恕我直言:
{}.tap do |my_hash| my_hash[:a] = 'a' my_hash[:b] = 'b' if condition end
有兴趣看到其他的答案,但这是我能想到的最好的一个单线(我也是一个单一的线程出了名的不好:P)
{:a => 'a'}.merge( condition ? {:b => 'b'} : {} )
在Rails上:
{a: 'asd', b: nil}.compact => {:a=>"asd"}
Hash[:a, 'a', *([:b, 'b'] if condition1), *([:c, 'c'] if condition2)]
这依赖于*nil
ruby在ruby中虚扩展的事实。 在ruby1.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]
这里有很多聪明的解决scheme,但IMO是最简单的,因此也是最好的方法
hash = { a: 'a', b: 'b' } hash[:c] = 'c' if condition
这违背了OP的两行要求,但其他答案似乎只有一行。 让我们面对它,这是最简单的解决scheme,它很容易阅读。
如果你有多个条件和逻辑,其他人需要了解后,那么我build议这不是一个class轮的好候选人。 根据所需的逻辑正确地创build你的哈希将更有意义。
这一个很好的多个条件。
( hash = {:a => 'a'}.tap {|h| h.store( *[(:b if condition_b), 'b'] ) h.store( *[(:c if condition_c), 'c'] ) } ).delete(nil)
请注意,我select了nil作为“垃圾”键,当你完成后会被删除。 如果您需要使用零键存储实际值,只需将存储条件更改为如下所示:
(condition_b ? :b : garbage_key)
然后在最后删除(garbage_key)。
这个解决scheme还将保持现有的零值不变,例如,如果在原始散列中有:a =>零,则不会被删除。
在Ruby 2.0中,与数组(和位置参数)的旧splat运算符( *
)类比,散列(和关键字参数)有一个双splat运算符( **
)。 所以你可以说:
{a: 'b', **(condition ? {b: 'b'} : {})}
hash, hash_new = {:a => ['a', true], :b => ['b', false]}, {} hash.each_pair{|k,v| hash_new[k] = v[1] ? v : nil } puts hash_new
我的单线解决scheme:
{:a => 'a'}.tap { |h| h.merge!(:b => 'b') if condition }
eval("{:a => 'a' #{', :b => \'b\'' if condition }}")
甚至
eval("{#{[":a => 'a'", (":b=>'b'" if ax)].compact.join(',')}}")
为更简单的添加条件