Forum: Ruby Proper way to either create or append to an array?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Adam B. (Guest)
on 2007-01-20 19:55
Hi all.

Let's say I want to either create a new named array or append to that
array if it already exists. Is there a more elegant way of doing the
following?

>> @foo[:bar].nil? ? foo[:bar] = ["snafu"] : foo[:bar] << "snafu"

Thanks!

/afb
Vincent F. (Guest)
on 2007-01-20 20:03
(Received via mailing list)
Adam B. wrote:
> Hi all.
>
> Let's say I want to either create a new named array or append to that
> array if it already exists. Is there a more elegant way of doing the
> following?
>
>>> @foo[:bar].nil? ? foo[:bar] = ["snafu"] : foo[:bar] << "snafu"

  I would use:

@foo[:bar] ||= []
@foo[:bar] << "snafu"

  There probably is more compact, but I find this writing very readable
when you're used to it (though, admittedly somehow puzzling for the
beginners).

  Cheers,

  Vince
Gavin K. (Guest)
on 2007-01-20 20:10
(Received via mailing list)
Adam B. wrote:
> Let's say I want to either create a new named array or append to that
> array if it already exists. Is there a more elegant way of doing the
> following?
>
> >> @foo[:bar].nil? ? foo[:bar] = ["snafu"] : foo[:bar] << "snafu"

Dunno if you'd call it elegant, but I frequently write:

( @foo[:bar] ||= [] ) << "snafu"
Robert K. (Guest)
on 2007-01-20 20:13
(Received via mailing list)
On 20.01.2007 18:55, Adam B. wrote:
> Hi all.
>
> Let's say I want to either create a new named array or append to that
> array if it already exists. Is there a more elegant way of doing the
> following?
>
>>> @foo[:bar].nil? ? foo[:bar] = ["snafu"] : foo[:bar] << "snafu"

Since you're using a Hash the block constructor is the most elegant
solution IMHO:

def initialize
   @foo = Hash.new {|h,k| h[k]=[]}
   ...
end

def other_method
   ...
   @foo[:bar] << "snafu"
   ...
end

Kind regards

  robert
Gavin K. (Guest)
on 2007-01-20 20:17
(Received via mailing list)
Robert K. wrote:
> Since you're using a Hash the block constructor is the most elegant
> solution IMHO:
>
> def initialize
>    @foo = Hash.new {|h,k| h[k]=[]}
>    ...
> end

To be clear for those unfamiliar with this: any time you ask for the
value of a key that doesn't exist, the block will be called (which
creates a new empty array). This means you can never see this
particular Hash has a key, since:
  if @foo[ :bar ]
will always succeed, and create a (possibly unwanted) array instance in
the process.
Rob B. (Guest)
on 2007-01-20 20:38
(Received via mailing list)
On Jan 20, 2007, at 1:15 PM, Phrogz wrote:

> value of a key that doesn't exist, the block will be called (which
> creates a new empty array). This means you can never see this
> particular Hash has a key, since:
>   if @foo[ :bar ]
> will always succeed, and create a (possibly unwanted) array
> instance in
> the process.

That's only because you're not checking for the presence of a key
correctly:

 >> myhash = Hash.new { |h,k| h[k] = Array.new }
=> {}
 >> if myhash[:oops]
 >>   puts "nothing"
 >>   end
nothing
=> nil
 >> myhash
=> {:oops=>[]}
 >> if myhash.has_key? :missing
 >>   puts ":missing contains #{myhash[:missing] * ', '}"
 >>   end
=> nil
 >> myhash
=> {:oops=>[]}

If you know that your code isn't using the block initialization, then
the first form might be OK.  However, the #has_key? will always do
what you expect.  This is particularly true if the value can be nil
or false.

-Rob


Rob B.    http://agileconsultingllc.com
removed_email_address@domain.invalid
William J. (Guest)
on 2007-01-20 22:10
(Received via mailing list)
Rob B. wrote:
> >
> correctly:
>  >> if myhash.has_key? :missing
I prefer to use include?, since it also works on arrays:

irb(main):006:0> ['foo','bar'].include? 'bar'
=> true
William J. (Guest)
on 2007-01-20 22:30
(Received via mailing list)
Phrogz wrote:
> value of a key that doesn't exist, the block will be called (which
> creates a new empty array). This means you can never see this
> particular Hash has a key, since:
>   if @foo[ :bar ]
> will always succeed, and create a (possibly unwanted) array instance in
> the process.

What if foo[:bar] has been assigned a value of false?
That method of checking for the presence of a key is
too crude even for awk.  Note below that the mere
attempt to access the value of a key creates an
entry for that key if it doesn't already exist.

BEGIN {
  SUBSEP = "^"
  a[22,"yes"] = 88
  a[33] = 99

  # The wrong way.
  if ( a["bar"] )
    print "How did 'bar' get here?"
  # The right way.
  if ( "foo" in a )
    print "'foo' too?"
  # Any unauthorized entries?
  for (key in a)
    print key
}

---  output  -----
22^yes
33
bar
This topic is locked and can not be replied to.