Proper way to either create or append to an array?

A

Adam Block

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
 
P

Phrogz

Adam said:
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"
 
V

Vincent Fourmond

Adam said:
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
 
R

Robert Klemme

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
 
P

Phrogz

Robert said:
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.
 
R

Rob Biedenharn

Robert said:
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.

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[:eek:ops]
puts "nothing"
end
nothing
=> nil
myhash => {:eek:ops=>[]}
if myhash.has_key? :missing
puts ":missing contains #{myhash[:missing] * ', '}"
end => nil
myhash
=> {:eek:ops=>[]}

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 Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
W

William James

Rob said:
Robert said:
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.

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[:eek:ops]
puts "nothing"
end
nothing
=> nil
myhash => {:eek:ops=>[]}
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
 
W

William James

Phrogz said:
Robert said:
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.

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top