ruby散列中的条件键/值

时间:2011-04-21 23:12:40

标签: ruby

是否有一个很好的(一行)方式在ruby中编写一个哈希值,只有条件满足时才有一些条目?我想到了

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

但如果条件未满足,则会:b == nil。我意识到这可以在两行左右轻松完成,但在一行中会更好(例如将哈希值传递给函数时)。

我是否还缺少了另一个红宝石的惊人功能? ;)

12 个答案:

答案 0 :(得分:50)

从Ruby 1.9+开始,如果你想根据条件构建一个哈希,你可以使用tap,这是我最喜欢的东西。这将它分成多行,但更具可读性恕我直言:

{}.tap do |my_hash| 
  my_hash[:a] = 'a'
  my_hash[:b] = 'b' if condition
end

答案 1 :(得分:45)

您可以先使用key =>创建哈希值nil,当条件不满足时,然后删除值为nil的那些对。例如:

{ :a => 'a', :b => ('b' if cond) }.delete_if{ |k,v| v.nil? }

收益率,对于cond == true:

{:b=>"b", :a=>"a"}

和cond == false

{:a=>"a"} 

<强>更新

这是等效的 - 更简洁,并以ruby 1.9.3表示法:

{ a: 'a', b: ('b' if cond) }.reject{ |k,v| v.nil? }

更新Ruby 2.4 +

从ruby 2.4.0开始,您可以使用compact方法:

{ a: 'a', b: ('b' if cond) }.compact

答案 2 :(得分:23)

有兴趣看到其他答案,但这是我能想到的最好的单线(我在单线上也是出了名的坏事:P)

{:a => 'a'}.merge( condition ? {:b => 'b'} : {} )

答案 3 :(得分:20)

&gt; = Ruby 2.4:

{a: 'asd', b: nil}.compact
=> {:a=>"asd"}

答案 4 :(得分:6)

这里有很多聪明的解决方案,但IMO最简单也是最好的方法是

hash = { a: 'a', b: 'b' }
hash[:c] = 'c' if condition

这违反了OP的两行要求,但实际上其他答案看起来只是单行。让我们面对现实吧,这是最简单的解决方案,而且很容易理解。

答案 5 :(得分:4)

在Ruby 2.0中,对于数组(和位置参数),类似于旧的splat运算符(**),有一个双splat运算符(*)用于散列(和关键字参数)。所以你可以说:

{a: 'b', **(condition ? {b: 'b'} : {})}

答案 6 :(得分:1)

Hash[:a, 'a', *([:b, 'b'] if condition1), *([:c, 'c'] if condition2)]

这依赖于*nil在ruby 1.9中扩展为空白的事实。在ruby 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]

答案 7 :(得分:1)

如果你有其他人需要了解的多种条件和逻辑,那么我认为这不是一个很好的候选人。根据所需的逻辑正确创建哈希会更有意义。

答案 8 :(得分:1)

这个适用于多个条件。

(
  hash = {:a => 'a'}.tap {|h|
    h.store( *[(:b if condition_b), 'b'] )
    h.store( *[(:c if condition_c), 'c'] )
  }
).delete(nil)

请注意,我选择nil作为“垃圾”键,当你完成时它会被删除。如果您需要使用nil密钥存储实际值,只需将存储条件更改为:

(condition_b ? :b : garbage_key)

然后在最后删除(garbage_key)。

此解决方案还将保持现有的零值不变,例如如果你有:a =&gt;在原始哈希值中为nil,它不会被删除。

答案 9 :(得分:0)

hash, hash_new = {:a => ['a', true], :b => ['b', false]}, {}
hash.each_pair{|k,v| hash_new[k] = v[1] ? v : nil }
puts hash_new

答案 10 :(得分:0)

我的单线解决方案:

{:a => 'a'}.tap { |h| h.merge!(:b => 'b') if condition }

答案 11 :(得分:-4)

eval("{:a => 'a' #{', :b => \'b\'' if condition }}")

甚至

eval("{#{[":a => 'a'", (":b=>'b'" if ax)].compact.join(',')}}")

更简单的添加条件