# Hash#map

**URL:** <https://www.ruby-forum.com/t/hash-map/166752>\
**Category:** Ruby\
**Created:** [April 29, 2009, 8:04am UTC](https://www.ruby-forum.com/t/hash-map/166752 "2009-04-29T08:04:32Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 29, 2009, 8:04am UTC](https://www.ruby-forum.com/t/hash-map/166752/1 "2009-04-29T08:04:32Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 29, 2009, 8:14am UTC](https://www.ruby-forum.com/t/hash-map/166752/2 "2009-04-29T08:14:31Z")

</div>

On Wed, Apr 29, 2009 at 8:00 AM, Fredrik [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> end  
> end  
> end
> 
> Regards,  
> Fredrik

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

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

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

(1..4).collect {|i| i\*i } #=\> [1, 4, 9, 16]  
(1..4).collect { “cat” } #=\> [“cat”, “cat”, “cat”, “cat”]

Andrew T.  
[http://ramblingsonrails.com](http://ramblingsonrails.com)  
[http://www.linkedin.com/in/andrewtimberlake](http://www.linkedin.com/in/andrewtimberlake)

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

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 29, 2009, 8:21am UTC](https://www.ruby-forum.com/t/hash-map/166752/3 "2009-04-29T08:21:01Z")

</div>

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}

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 29, 2009, 8:30am UTC](https://www.ruby-forum.com/t/hash-map/166752/4 "2009-04-29T08:30:28Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 29, 2009, 2:40pm UTC](https://www.ruby-forum.com/t/hash-map/166752/5 "2009-04-29T14:40:17Z")

</div>

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 G. II

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 29, 2009, 8:35am UTC](https://www.ruby-forum.com/t/hash-map/166752/6 "2009-04-29T08:35:24Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 30, 2009, 1:10am UTC](https://www.ruby-forum.com/t/hash-map/166752/7 "2009-04-30T01:10:34Z")

</div>

> 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 ?

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 30, 2009, 1:21am UTC](https://www.ruby-forum.com/t/hash-map/166752/8 "2009-04-30T01:21:06Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 30, 2009, 5:28am UTC](https://www.ruby-forum.com/t/hash-map/166752/9 "2009-04-30T05:28:06Z")

</div>

On 29 Apr, 21:39, James G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> newhash = oldhash.each\_with\_object({}) { |(k, v), h|  
> h[k] = some\_operation(v)
> 
> }
> 
> Hope that helps.
> 
> James Edward G. 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.)

---

<div class="post-metadata">

**Author:** ![Fredrik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/cab0a1/32.png) [@Fredrik](https://www.ruby-forum.com/u/Fredrik)\
**Post date:** [April 12, 2014, 12:28am UTC](https://www.ruby-forum.com/t/hash-map/166752/10 "2014-04-12T00:28:54Z")

</div>

KDr2 wrote in post #811055:

> 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}

Awesome, thanks!
