有条件的键/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(',')}}") 

为更简单的添加条件