我正在使用Ruby on Rails 3.0.10,我想以条件方式构建一个哈希键\值对。也就是说,如果条件匹配,我想添加一个键及其相关值:
hash = {
:key1 => value1,
:key2 => value2, # This key2\value2 pair should be added only 'if condition' is 'true'
:key3 => value3,
...
}
我怎么能这样做并保持代码的“良好”可读性?我是否“被迫”使用merge
方法?
我更喜欢tap
,因为我认为它提供了比这里描述的更清晰的解决方案,不需要任何hacky删除元素,并清楚地定义哈希的构建范围。
这也意味着你不需要声明一个我总是讨厌的不必要的局部变量。
如果您之前没有碰到它,tap
非常简单 - 它是Object
上的一个方法,它接受一个块并始终返回它被调用的对象。因此,要有条件地构建哈希,您可以这样做:
Hash.new.tap do |my_hash|
my_hash[:x] = 1 if condition_1
my_hash[:y] = 2 if condition_2
...
end
tap
有许多有趣的用途,这只是一个。
和Chris Jester-Young一样,带有轻微的可读性技巧
def cond(x)
condition ? x : :delete_me
end
hash = {
:key1 => value1,
:key2 => cond(value2),
:key3 => value3
}
然后进行后处理以删除:delete_me
条目
功能方法:
hash = {
:key1 => 1,
:key2 => (2 if condition),
:key3 => 3,
}.compact
注意:对于Ruby <2.4.0或不使用active-support,请用.compact
替换.reject { |k, v| v.nil? }
。
如果您担心可读性,可能最好保持简单:
hash = {}
hash[:key1] = value1
hash[:key2] = value2 if condition?
hash[:key3] = value3
...
把事情简单化:
hash = {
key1: value1,
key3: value3,
}
hash[:key2] = value2 if condition
通过这种方式,您还可以直观地分离您的特殊情况,如果它隐藏在散列字面值分配中,则可能会被忽略。
我使用merge
和三元运算符来处理这种情况,
hash = {
:key1 => value1,
:key3 => value3,
...
}.merge(condition ? {:key2 => value2} : {})
首先构建你的哈希:
hash = {
:key1 => value1,
:key2 => condition ? value2 : :delete_me,
:key3 => value3
}
然后在构建哈希之后执行此操作:
hash.delete_if {|_, v| v == :delete_me}
除非您的哈希被冻结或以其他方式不可变,否则这实际上只会保留存在的值。
如果您从某种Enumerable数据构建哈希,则可以使用inject,例如:
raw_data.inject({}){ |a,e| a[e.name] = e.value if expr; a }
很简单:
hash = {
:key1 => value1,
**(condition ? {key2: value2} : {})
}
希望能帮助到你!
如果您从其他位置的可选属性填充哈希值,则使用fetch非常有用。看看这个例子:
def create_watchable_data(attrs = {})
return WatchableData.new({
id: attrs.fetch(:id, '/catalog/titles/breaking_bad_2_737'),
titles: attrs.fetch(:titles, ['737']),
url: attrs.fetch(:url, 'http://www.netflix.com/shows/breaking_bad/3423432'),
year: attrs.fetch(:year, '1993'),
watchable_type: attrs.fetch(:watchable_type, 'Show'),
season_title: attrs.fetch(:season_title, 'Season 2'),
show_title: attrs.fetch(:id, 'Breaking Bad')
})
end