Forum: Ruby Hash#map

5feab09c8481f57ab1c6089a31b39359?d=identicon&s=25 Fredrik (Guest)
on 2009-04-29 08:04
(Received via mailing list)
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
5772c599ccab3081e0fffb1d54f3b6de?d=identicon&s=25 Andrew Timberlake (andrewtimberlake)
on 2009-04-29 08:14
(Received via mailing list)
On Wed, Apr 29, 2009 at 8:00 AM, Fredrik <fredjoha@gmail.com> 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 Timberlake
http://ramblingsonrails.com
http://www.linkedin.com/in/andrewtimberlake

"I have never let my schooling interfere with my education" - Mark Twain
A20f57356110f62f93f7555a4bbb96af?d=identicon&s=25 KDr2 (Guest)
on 2009-04-29 08:21
(Received via mailing list)
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}
1e736afdcdfe0753d67a81d449aca590?d=identicon&s=25 Srijayanth Sridhar (Guest)
on 2009-04-29 08:30
(Received via mailing list)
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
54404bcac0f45bf1c8e8b827cd9bb709?d=identicon&s=25 7stud -- (7stud)
on 2009-04-29 08:35
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.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-04-29 14:40
(Received via mailing list)
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
5feab09c8481f57ab1c6089a31b39359?d=identicon&s=25 Fredrik (Guest)
on 2009-04-30 01:10
(Received via mailing list)
>
> 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 ?
5feab09c8481f57ab1c6089a31b39359?d=identicon&s=25 Fredrik (Guest)
on 2009-04-30 01:21
(Received via mailing list)
> 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.
5feab09c8481f57ab1c6089a31b39359?d=identicon&s=25 Fredrik (Guest)
on 2009-04-30 05:28
(Received via mailing list)
On 29 Apr, 21:39, James Gray <ja...@grayproductions.net> wrote:
>
> 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.)
B8769b1ed68930f7adee6b6ed3425f2e?d=identicon&s=25 Evgeny G. (evgeny_g)
on 2014-04-12 00:28
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!
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.