Hash#map

Discussion in 'Ruby' started by Fredrik, Apr 29, 2009.

  1. Fredrik

    Fredrik Guest

    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
    Fredrik, Apr 29, 2009
    #1
    1. Advertising

  2. On Wed, Apr 29, 2009 at 8: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)? 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
    Andrew Timberlake, Apr 29, 2009
    #2
    1. Advertising

  3. Fredrik

    KDr2 Guest

    [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 <> 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.
    KDr2, Apr 29, 2009
    #3
  4. [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 <> 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
    >
    >
    Srijayanth Sridhar, Apr 29, 2009
    #4
  5. Fredrik

    7stud -- Guest

    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/.
    7stud --, Apr 29, 2009
    #5
  6. Fredrik

    Fredrik Guest

    > 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.
    Fredrik, Apr 29, 2009
    #6
  7. Fredrik

    Fredrik Guest

    >
    > 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 ?
    Fredrik, Apr 29, 2009
    #7
  8. Fredrik

    James Gray Guest

    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
    James Gray, Apr 29, 2009
    #8
  9. Fredrik

    Fredrik Guest

    On 29 Apr, 21:39, James Gray <> 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.)
    Fredrik, Apr 30, 2009
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Amit Bhatia

    Hash Map slower than Map.

    Amit Bhatia, Oct 8, 2007, in forum: C++
    Replies:
    7
    Views:
    359
    =?UTF-8?B?RXJpayBXaWtzdHLDtm0=?=
    Oct 9, 2007
  2. kl
    Replies:
    7
    Views:
    1,268
    James Kanze
    Jan 1, 2008
  3. navS
    Replies:
    3
    Views:
    485
    Ismo Salonen
    May 9, 2008
  4. rp
    Replies:
    1
    Views:
    478
    red floyd
    Nov 10, 2011
  5. Srijayanth Sridhar
    Replies:
    19
    Views:
    581
    David A. Black
    Jul 2, 2008
Loading...

Share This Page