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

Discussion in 'Ruby' started by Thomas W., Mar 3, 2011.

  1. Thomas W.

    Thomas W. Guest

    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?

    --
    Posted via http://www.ruby-forum.com/.
     
    Thomas W., Mar 3, 2011
    #1
    1. Advertising

  2. 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}

    --
    med vänlig hälsning
    David J. Hamilton
     
    David J.Hamilton, Mar 3, 2011
    #2
    1. Advertising

  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 ||=3D approach:

    hash[:key] ||=3D myvalue

    Michael Edgar

    http://carboni.ca/

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

    > hash =3D {}
    > hash[:key] =3D myvalue
    >=20
    >=20
    > How to assign hash[:key] only if myvalue is not nil?
    >=20
    > Current solution is:
    >=20
    > hash[:key] =3D myvalue unless myvalue.nil?
    >=20
    >=20
    > Is there something more beautiful?
    >=20
    > --=20
    > Posted via http://www.ruby-forum.com/.
    >=20
     
    Michael Edgar, Mar 3, 2011
    #3
  4. Thomas W.

    Mike Moore Guest

    On Thu, Mar 3, 2011 at 10:10 AM, Thomas W. <> wrote:
    >
    > hash =3D {}
    > =A0 =A0hash[:key] =3D myvalue
    >
    >
    > How to assign hash[:key] only if myvalue is not nil?
    >
    > Current solution is:
    >
    > =A0 =A0hash[:key] =3D myvalue unless myvalue.nil?
    >
    >
    > Is there something more beautiful?


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

    =A0 >> h =3D { :eek:ne =3D> 1, :two =3D> 2, :three =3D> nil, :four =3D> 4, :fi=
    ve =3D> nil }
    =A0 =3D> {:three=3D>nil, :four=3D>4, :five=3D>nil, :eek:ne=3D>1, :two=3D>2}
    =A0 >> h[:six] =3D 6
    =A0 =3D> 6
    =A0 >> h[:seven] =3D nil
    =A0 =3D> nil
    =A0 >> h.delete_if { |k, v| v.nil? }
    =A0 =3D> {:four=3D>4, :six=3D>6, :eek:ne=3D>1, :two=3D>2}
     
    Mike Moore, Mar 3, 2011
    #4
  5. Thomas W.

    Gary Wright Guest

    On Mar 3, 2011, at 12:10 PM, Thomas W. wrote:
    > Current solution is:
    >=20
    > hash[:key] =3D myvalue unless myvalue.nil?
    >=20
    > 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] =3D myvalue if myvalue

    would work. So would good old:

    if myvalue
    hash[:key] =3D 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 Wright=
     
    Gary Wright, Mar 3, 2011
    #5
  6. Thomas W.

    Gary Wright Guest

    On Mar 3, 2011, at 12:38 PM, Michael Edgar 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 ||=3D approach:
    >=20
    > hash[:key] ||=3D 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 Wright=
     
    Gary Wright, Mar 3, 2011
    #6
  7. Whoa, whoops, completely misread that. Early morning e-mail, disregard.

    Michael Edgar

    http://carboni.ca/

    On Mar 3, 2011, at 12:46 PM, Gary Wright wrote:

    >=20
    > On Mar 3, 2011, at 12:38 PM, Michael Edgar wrote:
    >=20
    >> 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 ||=3D approach:
    >>=20
    >> hash[:key] ||=3D myvalue

    >=20
    >=20
    > 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').
    >=20
    > Gary Wright
     
    Michael Edgar, Mar 3, 2011
    #7
  8. On 03.03.2011 18:38, Mike Moore wrote:
    > On Thu, Mar 3, 2011 at 10:10 AM, Thomas W.<> wrote:
    >>
    >> 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?

    >
    > You could assign the all values and then remove the just the nil
    > values afterward.
    >
    > >> h = { :eek:ne => 1, :two => 2, :three => nil, :four => 4, :five => nil }

    > => {:three=>nil, :four=>4, :five=>nil, :eek:ne=>1, :two=>2}
    > >> h[:six] = 6

    > => 6
    > >> h[:seven] = nil

    > => nil
    > >> h.delete_if { |k, v| v.nil? }

    > => {:four=>4, :six=>6, :eek:ne=>1, :two=>2}


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

    Cheers

    robert

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Mar 3, 2011
    #8
  9. Thomas W.

    Mike Moore Guest

    On Thu, Mar 3, 2011 at 10:55 AM, Robert Klemme
    <> wrote:
    > On 03.03.2011 18:38, Mike Moore wrote:
    >>
    >> On Thu, Mar 3, 2011 at 10:10 AM, Thomas W.<> =A0wr=

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

    >>
    >> You could assign the all values and then remove the just the nil
    >> values afterward.
    >>
    >> =A0 >> =A0h =3D { :eek:ne =3D> =A01, :two =3D> =A02, :three =3D> =A0nil, :f=

    our =3D> =A04, :five =3D>
    >> =A0nil }
    >> =A0 =3D> =A0{:three=3D>nil, :four=3D>4, :five=3D>nil, :eek:ne=3D>1, :two=3D=

    >2}
    >> =A0 >> =A0h[:six] =3D 6
    >> =A0 =3D> =A06
    >> =A0 >> =A0h[:seven] =3D nil
    >> =A0 =3D> =A0nil
    >> =A0 >> =A0h.delete_if { |k, v| v.nil? }
    >> =A0 =3D> =A0{:four=3D>4, :six=3D>6, :eek:ne=3D>1, :two=3D>2}

    >
    > Oh, this is so ugly. =A0And also potentially inefficient since the hash t=

    able
    > 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.
     
    Mike Moore, Mar 3, 2011
    #9
  10. On Thu, Mar 3, 2011 at 7:27 PM, Mike Moore <> wrote:
    > On Thu, Mar 3, 2011 at 10:55 AM, Robert Klemme
    > <> wrote:
    >> On 03.03.2011 18:38, Mike Moore wrote:


    >>> You could assign the all values and then remove the just the nil
    >>> values afterward.
    >>>
    >>> =A0 >> =A0h =3D { :eek:ne =3D> =A01, :two =3D> =A02, :three =3D> =A0nil, :=

    four =3D> =A04, :five =3D>
    >>> =A0nil }
    >>> =A0 =3D> =A0{:three=3D>nil, :four=3D>4, :five=3D>nil, :eek:ne=3D>1, :two=

    =3D>2}
    >>> =A0 >> =A0h[:six] =3D 6
    >>> =A0 =3D> =A06
    >>> =A0 >> =A0h[:seven] =3D nil
    >>> =A0 =3D> =A0nil
    >>> =A0 >> =A0h.delete_if { |k, v| v.nil? }
    >>> =A0 =3D> =A0{:four=3D>4, :six=3D>6, :eek:ne=3D>1, :two=3D>2}

    >>
    >> Oh, this is so ugly. =A0And 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

    --=20
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Mar 4, 2011
    #10
  11. Thomas W.

    Mike Moore Guest

    On Fri, Mar 4, 2011 at 3:05 AM, Robert Klemme
    <> wrote:
    >
    > If you want to clearly communicate the intent you can add a comment or
    > an assert statement to that effect. =A0First 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. =A0Now how is that
    > beautiful?


    Ouch. So its ugly *AND* buggy...

    # Check for nil values on hash assignment
    # Assuming false is a valid value
    h =3D {}
    h[:eek:ne] =3D one if !one.nil? # local method
    h[:two] =3D some_obj.two_method if !some_obj.two_method.nil?
    tmp =3D expensive_format_three(some_obj, some_other_obj)
    h[:three] =3D tmp if !tmp.nil?
    h

    # Delete nil values after hash assignment
    h =3D {
    :eek:ne =3D> one, # local method
    :two =3D> some_obj.two_method,
    :three =3D> expensive_format_three(some_obj, some_other_obj)
    }.delete_if { |k, v| v.nil? }
     
    Mike Moore, Mar 4, 2011
    #11
  12. On Fri, Mar 4, 2011 at 3:20 PM, Mike Moore <> wrote:
    > On Fri, Mar 4, 2011 at 3:05 AM, Robert Klemme
    > <> wrote:
    >> If you want to clearly communicate the intent you can add a comment or
    >> an assert statement to that effect. =A0First inserting something that is
    >> removed later is totally backwards.

    >
    > I'm sure there are cases where removing values from a hash is appropriate=
     
    Colin Bartlett, Mar 4, 2011
    #12
  13. Thomas W.

    Mike Moore Guest

    On Fri, Mar 4, 2011 at 10:56 AM, Colin Bartlett <> w=
    rote:
    >
    > I'm not sure what that code does, but taking what the OP wanted to do
    > as the starting point.
    >> hash =3D {}
    >> =A0 =A0hash[:key] =3D myvalue
    >> How to assign hash[:key] only if myvalue is not nil?
    >> Current solution is:
    >> =A0 =A0hash[:key] =3D 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.
     
    Mike Moore, Mar 4, 2011
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. rp
    Replies:
    1
    Views:
    533
    red floyd
    Nov 10, 2011
  2. Brian Candler

    puts nil generates "nil\n"

    Brian Candler, Nov 6, 2004, in forum: Ruby
    Replies:
    1
    Views:
    112
  3. Christoffer Sawicki
    Replies:
    5
    Views:
    261
    Christoffer Sawicki
    Sep 2, 2006
  4. Jay Levitt
    Replies:
    19
    Views:
    242
    Steve Austen
    Nov 29, 2010
  5. Replies:
    1
    Views:
    142
    Peña, Botp
    May 27, 2008
Loading...

Share This Page