Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Hash#map

Reply
Thread Tools

Hash#map

 
 
Fredrik
Guest
Posts: n/a
 
      04-29-2009
Is there any good reason why Hash#map does not give back a Hash (Ruby
1.8 but same in 1.9 as far as I know)? I often find myself writing
these kind of things:

newhash = oldhash.inject({}) { |h,(k,v)| h[k] = some_operation(v); h }

but that doesn't look pretty at all in my opinion. I want to just
write like this:

newhash = oldhash.map { |k,v| some_operation(v) }

I finally got around to change this behaviour for my own code, but are
all Ruby users supposed to invent this wheel on their own? Wouldn't it
be better if Hash#map behaved like this? Or is there something I am
missing?

class Hash
def hashmap
self.inject({}) do |newhash, (k,v)|
newhash[k] = yield(k, v)
newhash
end
end
end


Regards,
Fredrik
 
Reply With Quote
 
 
 
 
Andrew Timberlake
Guest
Posts: n/a
 
      04-29-2009
On Wed, Apr 29, 2009 at 8:00 AM, Fredrik <(E-Mail Removed)> wrote:
> Is there any good reason why Hash#map does not give back a Hash (Ruby
> 1.8 but same in 1.9 as far as I know)? I often find myself writing
> these kind of things:
>
> newhash =3D oldhash.inject({}) { |h,(k,v)| h[k] =3D some_operation(v); h =

}
>
> but that doesn't look pretty at all in my opinion. I want to just
> write like this:
>
> newhash =3D oldhash.map { |k,v| some_operation(v) }
>
> I finally got around to change this behaviour for my own code, but are
> all Ruby users supposed to invent this wheel on their own? Wouldn't it
> be better if Hash#map behaved like this? Or is there something I am
> missing?
>
> class Hash
> =A0def hashmap
> =A0 =A0self.inject({}) do |newhash, (k,v)|
> =A0 =A0 =A0newhash[k] =3D yield(k, v)
> =A0 =A0 =A0newhash
> =A0 =A0end
> =A0end
> end
>
>
> Regards,
> Fredrik
>


Becuase #map comes from form Enumerable (and is an alias for collect)

enum.collect {| obj | block } =3D> array
enum.map {| obj | block } =3D> array

Returns a new array with the results of running block once for every
element in enum.

(1..4).collect {|i| i*i } #=3D> [1, 4, 9, 16]
(1..4).collect { "cat" } #=3D> ["cat", "cat", "cat", "cat"]


Andrew Timberlake
http://ramblingsonrails.com
http://www.linkedin.com/in/andrewtimberlake

"I have never let my schooling interfere with my education" - Mark Twain

 
Reply With Quote
 
 
 
 
KDr2
Guest
Posts: n/a
 
      04-29-2009
[Note: parts of this message were removed to make it a legal post.]

irb(main):041:0> o={"a",1,"b",2}
=> {"a"=>1, "b"=>2}
irb(main):042:0> o.merge(o){|k,ov|ov*2}
=> {"a"=>2, "b"=>4}


On Wed, Apr 29, 2009 at 2:00 PM, Fredrik <(E-Mail Removed)> wrote:

> Is there any good reason why Hash#map does not give back a Hash (Ruby
> 1.8 but same in 1.9 as far as I know)? I often find myself writing
> these kind of things:
>
> newhash = oldhash.inject({}) { |h,(k,v)| h[k] = some_operation(v); h }
>
> but that doesn't look pretty at all in my opinion. I want to just
> write like this:
>
> newhash = oldhash.map { |k,v| some_operation(v) }
>
> I finally got around to change this behaviour for my own code, but are
> all Ruby users supposed to invent this wheel on their own? Wouldn't it
> be better if Hash#map behaved like this? Or is there something I am
> missing?
>
> class Hash
> def hashmap
> self.inject({}) do |newhash, (k,v)|
> newhash[k] = yield(k, v)
> newhash
> end
> end
> end
>
>
> Regards,
> Fredrik
>
>



--
Best Regards,
-- KDr2, at x-macro.com.

 
Reply With Quote
 
Srijayanth Sridhar
Guest
Posts: n/a
 
      04-29-2009
[Note: parts of this message were removed to make it a legal post.]

class Hash
def new_map
result = self.map do |k,v|
r = yield v
[k,r]
end
Hash[*result.flatten]
end
end

a = {}
a[2] = 4
a[3] = 6

b=a.new_map do |v|
v+2
end

puts b.class
puts b.inspect

yields:

Hash
{2=>6, 3=>8}

Does this help?

Jayanth

On Wed, Apr 29, 2009 at 11:30 AM, Fredrik <(E-Mail Removed)> wrote:

> Is there any good reason why Hash#map does not give back a Hash (Ruby
> 1.8 but same in 1.9 as far as I know)? I often find myself writing
> these kind of things:
>
> newhash = oldhash.inject({}) { |h,(k,v)| h[k] = some_operation(v); h }
>
> but that doesn't look pretty at all in my opinion. I want to just
> write like this:
>
> newhash = oldhash.map { |k,v| some_operation(v) }
>
> I finally got around to change this behaviour for my own code, but are
> all Ruby users supposed to invent this wheel on their own? Wouldn't it
> be better if Hash#map behaved like this? Or is there something I am
> missing?
>
> class Hash
> def hashmap
> self.inject({}) do |newhash, (k,v)|
> newhash[k] = yield(k, v)
> newhash
> end
> end
> end
>
>
> Regards,
> Fredrik
>
>


 
Reply With Quote
 
7stud --
Guest
Posts: n/a
 
      04-29-2009
Fredrik wrote:
> Is there any good reason why Hash#map does not give back a Hash (Ruby
> 1.8 but same in 1.9 as far as I know)? I often find myself writing
> these kind of things:
>
> newhash = oldhash.inject({}) { |h,(k,v)| h[k] = some_operation(v); h }
>
> but that doesn't look pretty at all in my opinion. I want to just
> write like this:
>
> newhash = oldhash.map { |k,v| some_operation(v) }
>


class Hash
def hashbackmap
result = {}

self.each do |key, val|
result[key] = yield val
end

result
end
end

h = {
"red" => 10,
"blue" => 20,
"green" => 30
}

p h.hashbackmap {|x| x*2}

--output:--
{"green"=>60, "blue"=>40, "red"=>20}

I HAVE A PATENT!! My licensing fees are cheap: $10 mth.


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

 
Reply With Quote
 
Fredrik
Guest
Posts: n/a
 
      04-29-2009
> irb(main):041:0> o={"a",1,"b",2}
> => {"a"=>1, "b"=>2}
> irb(main):042:0> o.merge(o){|k,ov|ov*2}
> => {"a"=>2, "b"=>4}
>

Thanks! That's the piece missing from my Ruby skills! Though o.merge
(o) doesn't look as pedagogically clear as o.map, it'll have to do.
 
Reply With Quote
 
Fredrik
Guest
Posts: n/a
 
      04-29-2009
>
> Becuase #map comes from form Enumerable (and is an alias for collect)
>


Well ok, that is a reason but it's not a good motivation why it HAS to
be like that. What use does one really have of getting an Array (with
elements in an undefined order) from a Hash#map ?
 
Reply With Quote
 
James Gray
Guest
Posts: n/a
 
      04-29-2009
On Apr 29, 2009, at 1:00 AM, Fredrik wrote:

> Is there any good reason why Hash#map does not give back a Hash (Ruby
> 1.8 but same in 1.9 as far as I know)?


It wouldn't make sense for Hash#map to return a Hash since you are not
required to transform it into key-value pairs:

>> {1 => "one", 2 => "two"}.map { |k, v| "#{k} is #{v}" }

=> ["1 is one", "2 is two"]

> I often find myself writing
> these kind of things:
>
> newhash = oldhash.inject({}) { |h,(k,v)| h[k] = some_operation(v); h }


1.9 adds each_with_object() for this very usage. You don't want the
return value of the block to carry forward, but instead the object you
started with. That's what each_with_object() does. So your code
becomes the following in Ruby 1.9:

newhash = oldhash.each_with_object({}) { |(k, v), h|
h[k] = some_operation(v)
}

Hope that helps.

James Edward Gray II


 
Reply With Quote
 
Fredrik
Guest
Posts: n/a
 
      04-30-2009
On 29 Apr, 21:39, James Gray <(E-Mail Removed)> wrote:
> On Apr 29, 2009, at 1:00 AM, Fredrik wrote:
>
> > Is there any good reason why Hash#map does not give back a Hash (Ruby
> > 1.8 but same in 1.9 as far as I know)?

>
> It wouldn't make sense for Hash#map to return a Hash since you are not *
> required to transform it into key-value pairs:
>
> *>> {1 => "one", 2 => "two"}.map { |k, v| "#{k} is #{v}" }
> => ["1 is one", "2 is two"]
>
> > I often find myself writing
> > these kind of things:

>
> > newhash = oldhash.inject({}) { |h,(k,v)| h[k] = some_operation(v); h }

>
> 1.9 adds each_with_object() for this very usage. *You don't want the *
> return value of the block to carry forward, but instead the object you *
> started with. *That's what each_with_object() does. *So your code *
> becomes the following in Ruby 1.9:
>
> newhash = oldhash.each_with_object({}) { |(k, v), h|
> * *h[k] = some_operation(v)
>
> }
>
> Hope that helps.
>
> James Edward Gray II


Thanks! It's not a very big improvement over inject though. I don't
see the use of Hash#map -> Array so if it was up to me, Hash#map would
give a Hash. If one really wants an Array it seems more reasonable to
use something like
hash.to_a{|k,v| "#{k} is #{v}" }

Maybe it's just me, but when I read "map" I am thinking "map this
block to each element and give back the same structure" (i.e.
Array#map gives an Array and Hash#map gives a Hash).

(I know map is just an alias for collect, but I never understood why
"collect" is a good name for this method.)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments