How to assign an element to a hash only if its value is not nil?

hash = {}
hash[:key] = myvalue

How to assign hash[:key] only if myvalue is not nil?

Current solution is:

hash[:key] = myvalue unless myvalue.nil?

Is there something more beautiful?

Excerpts from Thomas W.'s message of Thu Mar 03 09:10:26 -0800 2011:

How to assign hash[:key] only if myvalue is not nil?

Current solution is:

hash[:key] = myvalue unless myvalue.nil?

Is there something more beautiful?

There is an alternate way. Whether it is more beautiful or not is for
you to
decide.

myvalue and hash[:hey] = myvalue

ruby-1.9.2-p136 :001 > h, m, n = {}, 3, nil
=> [{}, 3, nil]
ruby-1.9.2-p136 :003 > m and h[:m] = m
=> 3
ruby-1.9.2-p136 :004 > n and h[:n] = n
=> nil
ruby-1.9.2-p136 :005 > h
=> {:m=>3}

If you don’t mind also overwriting the value if the value is false as
well as if the value is nil,
you can use the common ||= approach:

hash[:key] ||= myvalue

Michael E.
[email protected]
http://carboni.ca/

On Thu, Mar 3, 2011 at 10:10 AM, Thomas W. [email protected]
wrote:

Is there something more beautiful?

You could assign the all values and then remove the just the nil
values afterward.

h = { :one => 1, :two => 2, :three => nil, :four => 4, :five => nil
}
=> {:three=>nil, :four=>4, :five=>nil, :one=>1, :two=>2}

h[:six] = 6
=> 6

h[:seven] = nil
=> nil

h.delete_if { |k, v| v.nil? }
=> {:four=>4, :six=>6, :one=>1, :two=>2}

On Mar 3, 2011, at 12:38 PM, Michael E. wrote:

If you don’t mind also overwriting the value if the value is false as well as if
the value is nil,
you can use the common ||= approach:

hash[:key] ||= myvalue

That is different than what the OP described as it depends on the
existing value of hash[:key] but the OP wanted the assignment
conditional on the new value (‘myvalue’).

Gary W.

Whoa, whoops, completely misread that. Early morning e-mail, disregard.

Michael E.
[email protected]
http://carboni.ca/

On Mar 3, 2011, at 12:10 PM, Thomas W. wrote:

Current solution is:

hash[:key] = myvalue unless myvalue.nil?

Is there something more beautiful?

I tend to use #nil? and ‘unless’ sparingly and using them together like
this makes my brain work to hard.

Do you care specifically about distinguishing between nil and false? If
not:

hash[:key] = myvalue if myvalue

would work. So would good old:

if myvalue
hash[:key] = myvalue
end

or maybe

hash.store(key, myvalue) if myvalue

if you don’t like the look of the assignment.

What is your default value for the hash?
Do you need to avoid creating a key if myvalue is nil?

If nil is your default value and you don’t care about extra keys, then
just do the assignment regardless of the value of myvalue. I would even
suggest that you might want to arrange the rest of your code so that
this is true. The idea is to work with the grain of Hash’s normal
behavior rather than fight against it.

Gary W.

On 03.03.2011 18:38, Mike M. wrote:

hash[:key] = myvalue unless myvalue.nil?

=> 6

h[:seven] = nil
=> nil

h.delete_if { |k, v| v.nil? }
=> {:four=>4, :six=>6, :one=>1, :two=>2}

Oh, this is so ugly. And also potentially inefficient since the hash
table might grow larger than needed.

Cheers

robert

On Thu, Mar 3, 2011 at 7:27 PM, Mike M. [email protected] wrote:

On Thu, Mar 3, 2011 at 10:55 AM, Robert K.
[email protected] wrote:

On 03.03.2011 18:38, Mike M. wrote:

h.delete_if { |k, v| v.nil? }
=> {:four=>4, :six=>6, :one=>1, :two=>2}

Oh, this is so ugly. And also potentially inefficient since the hash table
might grow larger than needed.

I disagree. I think removing nil values afterwards is nicer (more
beautiful?) than having the check on every single assignment. And this
isn’t likely to be your bottleneck so trading a little inefficiency is
worthy of clearly communicating your intent, IMO.

If you want to clearly communicate the intent you can add a comment or
an assert statement to that effect. First inserting something that is
removed later is totally backwards. Plus, you might remove more than
intended, e.g. if there are nil values inserted previously and you
only want to avoid inserting nils during this method call. So, your
proposed solution is less efficient and error prone. Now how is that
beautiful?

Cheers

robert

On Thu, Mar 3, 2011 at 10:55 AM, Robert K.
[email protected] wrote:

Current solution is:
nil }
=> {:three=>nil, :four=>4, :five=>nil, :one=>1, :two=>2}

h[:six] = 6
=> 6

h[:seven] = nil
=> nil

h.delete_if { |k, v| v.nil? }
=> {:four=>4, :six=>6, :one=>1, :two=>2}

Oh, this is so ugly. And also potentially inefficient since the hash table
might grow larger than needed.

I disagree. I think removing nil values afterwards is nicer (more
beautiful?) than having the check on every single assignment. And this
isn’t likely to be your bottleneck so trading a little inefficiency is
worthy of clearly communicating your intent, IMO.

On Fri, Mar 4, 2011 at 3:05 AM, Robert K.
[email protected] wrote:

If you want to clearly communicate the intent you can add a comment or
an assert statement to that effect. First inserting something that is
removed later is totally backwards.

I’m sure there are cases where removing values from a hash is
appropriate.

Plus, you might remove more than
intended, e.g. if there are nil values inserted previously and you
only want to avoid inserting nils during this method call.

In that case where you don’t want to remove all nil values from a hash
you shouldn’t call delete_if { |k, v| v.nil? }

So, your
proposed solution is less efficient and error prone. Now how is that
beautiful?

Ouch. So its ugly AND buggy…

Check for nil values on hash assignment

Assuming false is a valid value

h = {}
h[:one] = one if !one.nil? # local method
h[:two] = some_obj.two_method if !some_obj.two_method.nil?
tmp = expensive_format_three(some_obj, some_other_obj)
h[:three] = tmp if !tmp.nil?
h

Delete nil values after hash assignment

h = {
:one => one, # local method
:two => some_obj.two_method,
:three => expensive_format_three(some_obj, some_other_obj)
}.delete_if { |k, v| v.nil? }

On Fri, Mar 4, 2011 at 3:20 PM, Mike M. [email protected] wrote:

On Fri, Mar 4, 2011 at 3:05 AM, Robert K.
[email protected] wrote:

If you want to clearly communicate the intent you can add a comment or
an assert statement to that effect. First inserting something that is
removed later is totally backwards.

I’m sure there are cases where removing values from a hash is appropriate.
Yes, but I think one of Robert K.'s points was why put values into
a hash only to remove them immediately.

Plus, you might remove more than intended,
e.g. if there are nil values inserted previously and you
only want to avoid inserting nils during this method call.

In that case where you don’t want to remove all nil values from a hash
you shouldn’t call delete_if { |k, v| v.nil? }
Which rather proves Robert K.'s point?

So, you proposed solution is less efficient and error prone.
Now how is that beautiful?
Ouch. So its ugly AND buggy…
I’ll avoid the beautiful/ugly debate. (I have some sympathy with
Dirac’s views on the necessity of “beauty” in theories, but at the end
of the day I’ll usually go with whatever overall works best, even if
it looks “ugly”.)

h = {
:one => one, # local method
:two => some_obj.two_method,
:three => expensive_format_three(some_obj, some_other_obj)
}.delete_if { |k, v| v.nil? }

I’m not sure what that code does, but taking what the OP wanted to do
as the starting point.

hash = {}
hash[:key] = myvalue
How to assign hash[:key] only if myvalue is not nil?
Current solution is:
hash[:key] = myvalue unless myvalue.nil?
Is there something more beautiful?

Again avoiding the “beauty question” (beauty is in the eye of the
beholder), that seems to me to do what the OP wants, and concisely
says what it’s doing.

I can see four problems with first assigning to the hash even if the
value is nil, and then deleting nil values from the hash. Robert
Klemme pointed out that it was inefficient, and that it might remove
previous wanted nil values in the hash.

Also, the code is longer, and you might override (and then delete) an
existing value if it has the same key as a new key & value pair in
which the value is nil: see what happens to :two in the following:

#ruby 1.9.1p430 (2010-08-16 revision 28998) [i386-mingw32]

hhh = { :zero => 0, :one => 1, :two => 2, :three => nil, :four => nil }
kv = [ [:one, 11], [:two, nil],
[:three, 33], [:four, nil],
[:five, 5], [:six, nil] ]

h = hhh.dup
puts; puts h.inspect
kv.each { |k, v| h[k] = v unless v.nil? }
puts “#=> #{h.inspect}”

{:zero=>0, :one=>1, :two=>2, :three=>nil, :four=>nil}

#=> {:zero=>0, :one=>11, :two=>2, :three=>33, :four=>nil, :five=>5}

h = hhh.dup
puts; puts h.inspect
kv.each { |k, v| h[k] = v }
h.delete_if { |k, v| v.nil? }
puts “#=> #{h.inspect}”

{:zero=>0, :one=>1, :two=>2, :three=>nil, :four=>nil}

#=> {:zero=>0, :one=>11, :three=>33, :five=>5}

On Fri, Mar 4, 2011 at 10:56 AM, Colin B.
[email protected] wrote:

I’m not sure what that code does, but taking what the OP wanted to do
as the starting point.

hash = {}
hash[:key] = myvalue
How to assign hash[:key] only if myvalue is not nil?
Current solution is:
hash[:key] = myvalue unless myvalue.nil?
Is there something more beautiful?

My assumption from the OP’s question was that he wanted to populate a
new hash so that the keys’s contain non-nil values. I offered a
slightly different approach to achieve the same result. (Please note I
said you “could”, not “should”.) My apologies for inflicting ugly or
dangerous code on you, I assumed the circumstances and tradeoffs
necessary for using (or not using) such an approach would be obvious.
My bad.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs