[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Proper way to either create or append to an array?

(Adam Block)

1/20/2007 5:56:00 PM

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

--
Posted via http://www.ruby-....

7 Answers

Gavin Kistner

1/20/2007 6:00:00 PM

0

Adam Block 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"

Vincent Fourmond

1/20/2007 6:02:00 PM

0

Adam Block 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

--
Vincent Fourmond, PhD student
http://vincent.fourmon...

Robert Klemme

1/20/2007 6:08:00 PM

0

On 20.01.2007 18:55, Adam Block 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 Kistner

1/20/2007 6:12:00 PM

0

Robert Klemme 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 Biedenharn

1/20/2007 6:37:00 PM

0


On Jan 20, 2007, at 1:15 PM, Phrogz wrote:

> Robert Klemme 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.

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 Biedenharn http://agileconsult...
Rob@AgileConsultingLLC.com



William James

1/20/2007 8:06:00 PM

0


Rob Biedenharn wrote:
> On Jan 20, 2007, at 1:15 PM, Phrogz wrote:
>
> > Robert Klemme 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.
>
> 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

I prefer to use include?, since it also works on arrays:

irb(main):006:0> ['foo','bar'].include? 'bar'
=> true

William James

1/20/2007 8:26:00 PM

0

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

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