what is the ruby way to do this?

A

ako...

hello,

i am still learning. in the below code @attributes is a hash table. i
want to add a new value 'a' for a key represented by 'a.key'. i also
want to group values with the same keys in to arrays. thanks for any
help.

konstantin

if @attributes.has_key?(a.key)
if @attributes[a.key].is_a?(Array)
@attributes[a.key] << a
else
@attributes[a.key] = [@attributes[a.key], a]
end
else
@attributes[a.key] = a
end
 
A

ako...

sorry, forgot to phrase the question. the question is is there a way to
make this code more compact and pretty?
 
J

JB Eriksson

------=_Part_33575_11574634.1132698171826
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

hello,

i am still learning. in the below code @attributes is a hash table. i
want to add a new value 'a' for a key represented by 'a.key'. i also
want to group values with the same keys in to arrays. thanks for any
help.

konstantin

if @attributes.has_key?(a.key)
if @attributes[a.key].is_a?(Array)
@attributes[a.key] << a
else
@attributes[a.key] =3D [@attributes[a.key], a]
end
else
@attributes[a.key] =3D a
end
Pardon my question, but isn't the whole point of hashes that every key is
unique?

------=_Part_33575_11574634.1132698171826--
 
L

Lyndon Samson

------=_Part_17900_9817640.1132698449982
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

$hash =3D {}

def add(key, val)
if $hash.has_key?(key)
if $hash[key].is_a?(Array)
$hash[key] << val
else
$hash[key] =3D [$hash[key], val]
end
else
$hash[key] =3D val
end
end

def add2(key, val)
if $hash.has_key?(key)
$hash[key].to_a << val
else
$hash[key] =3D val.to_a
end
end

key =3D "a"
val =3D "aval"
add2(key, val)
puts $hash.inspect

key =3D "a"
val =3D "aval2"
add2(key, val)
puts $hash.inspect

------=_Part_17900_9817640.1132698449982--
 
A

ako...

yes, this is the point of hashes. in my program, i have attributes with
names (keys). i want to collect these attributes in to a data
structure. attributes with the same names form an array. like in a HTTP
POST form, if you have fields with the same names they are treated as
an array.
 
L

Lyndon Samson

------=_Part_17944_26013144.1132698665165
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

and this monstrosity, which isn't in the spirit of ruby... :)

def add3(key, val)
$hash[key] =3D ( $hash[key] =3D=3D nil ) ? val.to_a : $hash[key] << val
end

------=_Part_17944_26013144.1132698665165--
 
R

Ryan Leavengood

hello,

i am still learning. in the below code @attributes is a hash table. i
want to add a new value 'a' for a key represented by 'a.key'. i also
want to group values with the same keys in to arrays. thanks for any
help.

konstantin

if @attributes.has_key?(a.key)
if @attributes[a.key].is_a?(Array)
@attributes[a.key] << a
else
@attributes[a.key] =3D [@attributes[a.key], a]
end
else
@attributes[a.key] =3D a
end

This is a fairly standard Ruby idiom (a hash of arrays):

(@attributes[a.key]||=3D[])<<a

What the above is doing is setting the entry for a.key to an empty
array if nothing exists, otherwise it will return the array already at
that location. Then the element a is added to that array.

Ryan
 
R

Ryan Leavengood

yes, this is the point of hashes. in my program, i have attributes with
names (keys). i want to collect these attributes in to a data
structure. attributes with the same names form an array. like in a HTTP
POST form, if you have fields with the same names they are treated as
an array.

In my opinion it is better to just put all the attributes into an
array (which is what my code does), even the single ones, that way you
can treat all the hashtable entries the same way (since they will all
be arrays.)

Ryan
 
K

Ken Kunz

Konstantin,

When you have a single attribute associated with a key, is it
acceptable to have it in a one-element array? If so, you could do
something like:

@attributes = {}
....
@attributes[a.key] ||= []
@attributes[a.key] << a

Or, if you don't mind having empty keys return an empty array instead
of nil, you could do:

@attributes = Hash.new([])
....
@attributes[a.key] << a

Cheers,
Ken
 
A

ako...

thank you. this assumes that the hash's default value is nil. but this
is a good enough assumption for my purposes. i was hoping to avoid
creating one-element arrays and still have the simplicity of a single
line solution but i guess this cant be done. thanks for your help.

konstantin
 
L

Lyndon Samson

------=_Part_18000_11089037.1132699183484
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

And finally I get to

def add4(key, val)
$hash[key]=3D $hash[key].to_a << val
end

These mean your values are allways arrays, but thats no problem right?

------=_Part_18000_11089037.1132699183484--
 
B

Bill Kelly

Hi,

From: "ako... said:
i am still learning. in the below code @attributes is a hash table. i
want to add a new value 'a' for a key represented by 'a.key'. i also
want to group values with the same keys in to arrays. thanks for any
help.

if @attributes.has_key?(a.key)
if @attributes[a.key].is_a?(Array)
@attributes[a.key] << a
else
@attributes[a.key] = [@attributes[a.key], a]
end
else
@attributes[a.key] = a
end

An alternate approach might be:

@attributes = Hash.new {|h,k| h[k] = Array.new}

This will automatically create arrays to hold your keys, on demand.

Now you can just say:

@attributes["whatever"] << "something"
@attributes["foo"] << 123
@attributes["foo"] << 456

@attributes.inspect
{"foo"=>[123, 456], "whatever"=>["something"]}


Hope this helps,

Regards,

Bill
 
C

Caleb Tennis

Note that a "Ruby" hint would be to get rid of your "is_a?",
preferring to use "respond_to?" instead.

You could get fancier and just call "<<" on everything, catching
exceptions and handling them for objects that don't implement that
method.

Caleb
 
M

Mark Van Holstyn

------=_Part_4134_23588041.1132700157780
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Personally, I would keep every element of the hash an array. You can do tha=
t
like so...
def add4( key, value )
@hsh[key] =3D @hsh[key].to_a<<value
end


if you must keep entries in the hash that only have one value as single
elements and not as arrays..
def add5( key, value )
@hsh[key] =3D @hsh[key]?@hsh[key].to_a<<value:value
end

------=_Part_4134_23588041.1132700157780--
 
M

Matthew Desmarais

Ken said:
Konstantin,

When you have a single attribute associated with a key, is it
acceptable to have it in a one-element array? If so, you could do
something like:

@attributes = {}
....
@attributes[a.key] ||= []
@attributes[a.key] << a

Or, if you don't mind having empty keys return an empty array instead
of nil, you could do:

@attributes = Hash.new([])
....
@attributes[a.key] << a

Cheers,
Ken
Careful with this one. When you do this:

Hash.new([])

you set the default valued returned by the hash to an array. The
problem is that it will always return the same array. So in the example
provided above you will end up with an empty hash for @attributes.

What you really want is the default block style:
Hash.new{|hash, key| hash[key] = []}

This will create a new array for each key.

It's an extremely sneaky little problem.

Regards,
Matthew
 
J

James Britt

Bill said:
An alternate approach might be:

@attributes = Hash.new {|h,k| h[k] = Array.new}

This will automatically create arrays to hold your keys, on demand.

Now you can just say:

@attributes["whatever"] << "something"
@attributes["foo"] << 123
@attributes["foo"] << 456

@attributes.inspect
{"foo"=>[123, 456], "whatever"=>["something"]}



And, mixing some of the approaches shown:


@attributes = {}


# Assumes the given object quacks on 'key'
def @attributes.<<( keyed_obj )
(self[keyed_obj.key]||=[])<<keyed_obj
end


@attributes << a1
@attributes << a2
@attributes << a3



James

--

http://www.ruby-doc.org - Ruby Help & Documentation
http://www.artima.com/rubycs/ - Ruby Code & Style: Writers wanted
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com - Playing with Better Toys
http://www.30secondrule.com - Building Better Tools
 
M

Matthew Desmarais

ako... said:
sorry, what is 'ri'?
ri is a commend line program that may or may not have been installed
with your distribution of ruby. It's a viewer for the documentation
that was (hopefully) also installed with your disctribution of ruby.

If you type "ri Hash.new" it will display information on the class
method Hash.new. If you were to use the form "ri Hash#keys" then you
weould be requesting information about the instance method keys that may
be called on a hash object.

Try it, and if you don't have it installed then someone can help you get
it set up.

Regards,
Matthew
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top