[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Iterating through a hash

Brian Ross

8/20/2008 5:35:00 PM

[Note: parts of this message were removed to make it a legal post.]

How can I iterate through a hash so that each key is modified and saved into
a new hash?

# Beginning of code

hash = {"name"=>"greg", "job"=>"boring", "hair"=>"plenty"}
p hash

map = hash.each_key do |key|
key.upcase
end

p map

# End of code

I'd imagine that this would return map as a new hash with the keys modified.
Is there anything like collect! for hashes?

Brian

12 Answers

Patrick Doyle

8/20/2008 5:49:00 PM

0

How about something like:

map = {}
hash.each_pair do |k,v|
map[k.upcase] = v
end

--wpd

Farrel Lifson

8/20/2008 5:53:00 PM

0

2008/8/20 Brian Ross <p.brian.ross@gmail.com>:
> How can I iterate through a hash so that each key is modified and saved into
> a new hash?
>
> # Beginning of code
>
> hash = {"name"=>"greg", "job"=>"boring", "hair"=>"plenty"}
> p hash
>
> map = hash.each_key do |key|
> key.upcase
> end
>
> p map
>
> # End of code

Hash[*hash.map{|key,value| [key.upcase, value]}.flatten]

Farrel
--
Aimred - Ruby Development and Consulting
http://www....

Florian Gilcher

8/20/2008 6:13:00 PM

0

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

#upcase doesn't modify the receiver.

#upcase! doesn't work because you can't modify String keys, as they
are frozen.

So, you have to rebuild the hash, the others pointed out some
solutions for this.

Regards,
Florian Gilcher

On Aug 20, 2008, at 7:34 PM, Brian Ross wrote:

> How can I iterate through a hash so that each key is modified and
> saved into
> a new hash?
>
> # Beginning of code
>
> hash = {"name"=>"greg", "job"=>"boring", "hair"=>"plenty"}
> p hash
>
> map = hash.each_key do |key|
> key.upcase
> end
>
> p map
>
> # End of code
>
> I'd imagine that this would return map as a new hash with the keys
> modified.
> Is there anything like collect! for hashes?
>
> Brian

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkisX3AACgkQJA/zY0IIRZYC0ACfVfK1H80uupfXn/g0jhp69uzB
O4YAoMIao4OCp1WfSUkpTWKW3LQA3tKP
=WHKL
-----END PGP SIGNATURE-----

Robert Klemme

8/20/2008 6:30:00 PM

0

On 20.08.2008 19:34, Brian Ross wrote:
> How can I iterate through a hash so that each key is modified and saved into
> a new hash?
>
> # Beginning of code
>
> hash = {"name"=>"greg", "job"=>"boring", "hair"=>"plenty"}
> p hash
>
> map = hash.each_key do |key|
> key.upcase
> end
>
> p map
>
> # End of code
>
> I'd imagine that this would return map as a new hash with the keys modified.
> Is there anything like collect! for hashes?

Folks, thanks for leaving the #inject solution to me. :-)

map = hash.inject({}) do |h,(k,v)|
h[k.upcase] = v
h
end

Cheers

robert

Martin DeMello

8/20/2008 6:33:00 PM

0

On Wed, Aug 20, 2008 at 11:26 AM, Robert Klemme
<shortcutter@googlemail.com> wrote:
>
> Folks, thanks for leaving the #inject solution to me. :-)
>
> map = hash.inject({}) do |h,(k,v)|
> h[k.upcase] = v
> h
> end

without the ugly "h" at the end :) :

map = hash.inject({}) {|h, (k,v)| h.update({k.upcase => v})}

martin

Brian Ross

8/20/2008 7:49:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

On Wed, Aug 20, 2008 at 2:32 PM, Martin DeMello <martindemello@gmail.com>wrote:

> without the ugly "h" at the end :) :
>
> map = hash.inject({}) {|h, (k,v)| h.update({k.upcase => v})}
>

Thanks everyone! Using Martin's example, how would I then use upcase for an
array of hashes?

I'd imagine it would be

this_array.collect do |hash|
@map = {}
hash.each_pair do |k,v|
@map[k.upcase] = v
end
end

but while the @map gives me the scope to see it outside of the block, it
looks like only the first hash within the array is passed through.

Brian

Martin DeMello

8/20/2008 8:48:00 PM

0

On Wed, Aug 20, 2008 at 12:48 PM, Brian Ross <p.brian.ross@gmail.com> wrote:
>
> this_array.collect do |hash|
> @map = {}
> hash.each_pair do |k,v|
> @map[k.upcase] = v
> end
> end
>
> but while the @map gives me the scope to see it outside of the block, it
> looks like only the first hash within the array is passed through.

new_array = this_array.collect do |hash|
map = {}
hash.each_pair do |k,v|
map[k.upcase] = v
end
map
end

collect collects the return value of the block

martin

Robert Klemme

8/21/2008 7:42:00 AM

0

2008/8/20 Martin DeMello <martindemello@gmail.com>:
> On Wed, Aug 20, 2008 at 11:26 AM, Robert Klemme
> <shortcutter@googlemail.com> wrote:
>>
>> Folks, thanks for leaving the #inject solution to me. :-)
>>
>> map = hash.inject({}) do |h,(k,v)|
>> h[k.upcase] = v
>> h
>> end
>
> without the ugly "h" at the end :) :
>
> map = hash.inject({}) {|h, (k,v)| h.update({k.upcase => v})}

But with ugly and unnecessary brackets. This works as well

map = hash.inject({}) {|h, (k,v)| h.update(k.upcase => v)}

Note though that this unfortunately creates a lot of temporary Hashes
that are thrown away immediately. I personally find that more ugly
than the h at the end. You can reformat to make it less stand out as
in

map = hash.inject {} do |h,(k,v)|
h[k.upcase] = v; h
end

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

Peña, Botp

8/21/2008 8:40:00 AM

0

From: Brian Ross [mailto:p.brian.ross@gmail.com]=20
# I'd imagine that this would return map as a new hash with the=20
# keys modified. Is there anything like collect! for hashes?

the required pairings for hashes makes it fragile to implement a =
map/collect like feature similar to plain arrays.

you can create one if you like. just be careful.

eg, here is my simple-minded implementation,

irb(main):084:0> class Hash
irb(main):085:1> def map2
irb(main):086:2> h=3D{}
irb(main):087:2> self.each do |k,v|
irb(main):088:3* kk,vv=3Dyield(k,v)
irb(main):089:3> key =3D kk || k
irb(main):090:3> val =3D vv || v
irb(main):091:3> h[key] =3D val
irb(main):092:3> end
irb(main):093:2> h
irb(main):094:2> end
irb(main):095:1> end
=3D> nil
irb(main):096:0> hash.map2{|k,_| k.upcase}
=3D> {"NAME"=3D>"greg", "JOB"=3D>"boring", "HAIR"=3D>"plenty"}
irb(main):097:0> hash.map2{|k| k.upcase}
=3D> {"NAME"=3D>"greg", "JOB"=3D>"boring", "HAIR"=3D>"plenty"}
irb(main):098:0> hash.map2{|k,v| k.upcase}
=3D> {"NAME"=3D>"greg", "JOB"=3D>"boring", "HAIR"=3D>"plenty"}
irb(main):099:0> hash.map2{|k,v| [k.upcase,v.capitalize]}
=3D> {"NAME"=3D>"Greg", "JOB"=3D>"Boring", "HAIR"=3D>"Plenty"}


kind regards -botp





Robert Klemme

8/21/2008 11:25:00 AM

0

2008/8/21 Pe=F1a, Botp <botp@delmonte-phil.com>:
> From: Brian Ross [mailto:p.brian.ross@gmail.com]
> # I'd imagine that this would return map as a new hash with the
> # keys modified. Is there anything like collect! for hashes?
>
> the required pairings for hashes makes it fragile to implement a map/coll=
ect like feature similar to plain arrays.
>
> you can create one if you like. just be careful.
>
> eg, here is my simple-minded implementation,
>
> irb(main):084:0> class Hash
> irb(main):085:1> def map2
> irb(main):086:2> h=3D{}
> irb(main):087:2> self.each do |k,v|
> irb(main):088:3* kk,vv=3Dyield(k,v)
> irb(main):089:3> key =3D kk || k
> irb(main):090:3> val =3D vv || v
> irb(main):091:3> h[key] =3D val
> irb(main):092:3> end
> irb(main):093:2> h
> irb(main):094:2> end
> irb(main):095:1> end
> =3D> nil

I'd like to use that bit for a small discussion if you allow. I
believe the implementation would be better off by not messing with
return values from the block because the changes lead to more complex
code and results may be surprising (i.e. if you relied on returning
nil or false and expected that to show up in the new Hash). By having
the method do less things it becomes more flexible to use.

Another interesting question is which is the proper method for
creating the new Hash? I can think at least of these as reasonable
solutions

h =3D {}
h =3D Hash.new(default)
h =3D Hash.new(&default_proc)
h =3D default_proc ? Hash.new(&default_proc) : Hash.new(default)
h =3D self.class.new
h =3D self.class.new(default)
h =3D self.class.new(&default_proc)
h =3D dup.clear

The solution might be to do

def map2(h =3D {})
each do |k,v|
k, v =3D yield k, v
h[k] =3D v
end
h
end

i.e. allow the caller to decide where he wants the mapped data to go
while defaulting to the most straightforward case, a new Hash. This is
similar to what Enumerable#map does, i.e. it creates a new Array
regardless of the type at hand.

Kind regards

robert

--=20
use.inject do |as, often| as.you_can - without end