Conditional key/value in a ruby hash
UPDATE Ruby 2.4+
Since ruby 2.4.0, you can use the compact method:
{ a: 'a', b: ('b' if cond) }.compact
Original answer (Ruby 1.9.2)
You could first create the hash with key => nil for when the condition is not met, and then delete those pairs where the value is nil. For example:
{ :a => 'a', :b => ('b' if cond) }.delete_if{ |k,v| v.nil? }
yields, for cond == true:
{:b=>"b", :a=>"a"}
and for cond == false
{:a=>"a"}
UPDATE for ruby 1.9.3
This is equivalent - a bit more concise and in ruby 1.9.3 notation:
{ a: 'a', b: ('b' if cond) }.reject{ |k,v| v.nil? }
Ruby - how to add a conditional key to a hash?
Not the prettiest solution, but **
could be used:
{
key1: data.k1,
key2: data.k2,
**(@var == true ? { key3: data.k3 } : {}),
key4: data.k4,
}
Note that == true
can be omitted if you just care whether @var
is truthy.
Conditional inclusion of a key-value pair in a hash
def self.some_hash(some_key = nil)
{"foo" => "bar"}.merge(some_key ? {some_key => "yucky, long-winded syntax"} : {})
end
Or, if modifying the original hash,
def self.some_hash(some_key = nil)
{"foo" => "bar"}
.tap{|h| h.merge!(some_key => "yucky, long-winded syntax") if some_key}
end
Or, maybe you can do it in a way close to your original:
def self.some_hash(some_key = nil)
{"foo" => "bar"}
.tap{|h| h[some_key] = "yucky, long-winded syntax" if some_key}
end
Building a hash in a conditional way
I prefer tap
, as I think it provides a cleaner solution than the ones described here by not requiring any hacky deleting of elements and by clearly defining the scope in which the hash is being built.
It also means you don't need to declare an unnecessary local variable, which I always hate.
In case you haven't come across it before, tap
is very simple - it's a method on Object
that accepts a block and always returns the object it was called on. So to build up a hash conditionally you could do this:
Hash.new.tap do |my_hash|
my_hash[:x] = 1 if condition_1
my_hash[:y] = 2 if condition_2
...
end
There are many interesting uses for tap
, this is just one.
Conditionally set value of key in hash
You just need some brackets around the values:
def parse(issue)
{
#...
asignee_handle: (issue['assignee']['login'] if issue['assignee']),
#...
}
end
The value of the :asignee_handle
key will now either be issue['assignee']['login']
or it will be nil
(or you will get an error if issue['assignee']
isn’t a hash).
Ruby hash keys to array conditional on hash value
h.select { |_, v| v }.keys
Will do the same, but in more readable way.
Creating a key value pair based on a condition in a Ruby hash
You could use Hash#merge!
method to merge unique key value pairs based on condition.
parameters= {
'SearchIndex' => params[:searchIndex],
'Keywords' => params[:search_term]
}
case params[:searchindex]
when 'All'
parameters.merge!({ :'ResponseGroup' => 'ItemAttributes' })
else
parameters.merge!({ :'ResponseGroup' => 'ItemAttributes,Images', :'Sort' => 'salesrank' })
end
For every other searchindex you would add a when...
condition and merge!
the required attributes.
ruby do statements if hash key satisfies condition
I will just show how this can be done quite economically in Ruby. Until recently, when wanting to modify keys of a hash one usually would do one of two things:
- create a new empty hash and then add key/values pairs to the hash; or
- convert the hash to an array
a
of two-element arrays (key-value pairs), modify the first element of each element ofa
(the key) and then converta
to the desired hash.
Recently (with MRI v2.4) the Ruby monks bestowed on us the handy methods Hash#transform_keys and Hash#transform_keys!. We can use the first of these profitably here. First we need a regular expression to match keys.
r = /
\A # match beginning of string
first_type_ # match string
(\p{Lower}+) # match 1+ lowercase letters in capture group 1
\z # match the end of the string
/x # free-spacing regex definition mode
Conventionally, this is written
r = /\Afirst_type_(\p{Lower}+)\z/
The use of free-spacing mode makes the regex self-documenting. We now apply the transform_keys
method, together with the method String#sub and the regex just defined.
event = {"first_type_a"=>100, "first_type_b"=>false,
"second_type_a"=>"abc", "second_type_b"=>false}
event.transform_keys { |k| k.sub(r, "important.#{'\1'}_1") }
#=> {"important.a_1"=>100, "important.b_1"=>false,
# "second_type_a"=>"abc", "second_type_b"=>false}
In the regex the p{} construct expression \p{Lower}
could be replaced with \p{L}
, the POSIX bracket expression [[:lower:]]
(both match Unicode letters) or [a-z]
, but the last has the disadvantage that it will not match letters with diacritical marks. That includes letters of words borrowed from other languages that are used in English text (such as rosé, the wine). Search Regexp for documentation of POSIX and \p{}
expressions.
If "first_type_"
could be followed by lowercase or uppercase letters use \p{Alpha}
; if it could be followed by alphanumeric characters, use \p{Alnum}
, and so on.
Conditional set value in a ruby hash
Basing on Dave comment:
def stores_distances
site = Site.find params[ :id ]
distances = Store.current.map do |store|
{
name: store.name,
value: distance(site.address, store.address) || 'no precision address'
}
end
render json: {
distances: distances.to_json
}
end
def distance(site_address, store_address)
return nil unless store_address.latitude && store_address.longitude
Haversine.distance(
site_address.latitude,
site_address.longitude,
store_address.latitude,
store_address.longitude
).round(2)
end
Related Topics
How to Make a Ruby String Safe for a Filesystem
Rails 6.1, Ruby 3.0.0: Tests Error as They Cannot Load Rexml
Writing Over Previously Output Lines in the Command Prompt with Ruby
Is There a Shorter Way to Require a File in the Same Directory in Ruby
How to Randomly Iterate Through a Large Range
Maintaining Cookies Between Mechanize Requests
Error Running '_Rvm_Make Install'
How to Parse JSON Request Body in Sinatra Just Once and Expose It to All Routes
Custom Ruby Gem in Gemfile on Heroku
Does Ruby Have the Java Equivalent of Synchronize Keyword
Undef - Why Would You Want to Undefine a Method in Ruby
Git Deployment + Configuration Files + Heroku
Getting Webpage Content with Ruby -- I'm Having Troubles
How Would I Save Multiple Records at Once in Rails
Why Is 'Return a or B' a Void Value Expression Error in Ruby