Feature #6669

A method like Hash#map but returns hash

Added by Yutaka HARA almost 2 years ago. Updated about 1 year ago.

[ruby-core:45960]
Status:Feedback
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:next minor

Description

=begin
Given a hash h, h.map returns an array(alist), but sometimes I hope it returned a hash.

Example:

class Hash
def apply(&block)
self.inject({}) do |h, (k, v)|
newk, newv = *block.call(k, v)
h[newk] = newv
h
end
end
end

score = {
taro: [1,3,2],
jiro: [3,5,8,4],
saburo: [2,9]
}
maxscore = score.apply{|k,v| [k, v.max]}
#=> {taro: 3, jiro: 8, saburo: 9}
p max
score[:taro]
#=> 3

I'm not thinking "apply" is a perfect name for this. Maybe "hashmap" is better
(we already have "flat
map").
=end

6669.pdf - 1-page presentation slide for the feature request meeting ([ruby-dev:45708]) (41.7 KB) Yutaka HARA, 06/30/2012 02:27 AM


Related issues

Related to ruby-trunk - Feature #4151: Enumerable#categorize Assigned
Related to ruby-trunk - Feature #7292: Enumerable#to_h Closed 11/07/2012
Related to ruby-trunk - Feature #7793: New methods on Hash Assigned 02/07/2013

History

#1 Updated by Yutaka HARA almost 2 years ago

Adding presentation slide for the feature request meeting ()

#2 Updated by Thomas Sawyer almost 2 years ago

Hi, I just want to mention that Facets has this using name #mash (map hash) with alias #graph, which was the original name. So those are two names to consider. Thanks.

#3 Updated by Yusuke Endoh almost 2 years ago

  • Status changed from Open to Assigned
  • Assignee set to Yukihiro Matsumoto

Received, thank you!

Yusuke Endoh mame@tsg.ne.jp

#4 Updated by Yukihiro Matsumoto over 1 year ago

Since Hash#reject, Hash#select does return a hash, I think it's OK for Hash#collect to return a hash.

I believe Hash#map should return an array as before, just like find_all does.

Matz.

#5 Updated by Martin Dürst over 1 year ago

On 2012/07/21 18:12, matz (Yukihiro Matsumoto) wrote:

Issue #6669 has been updated by matz (Yukihiro Matsumoto).

Since Hash#reject, Hash#select does return a hash, I think it's OK for Hash#collect to return a hash.

I believe Hash#map should return an array as before, just like find_all does.

Matz.

Wouldn't it be really confusing that for Arrays, #map and #collect are
synonyms, but for Hash, they are different?

Regards, Martin.

#6 Updated by Marc-Andre Lafortune over 1 year ago

Hi,

duerst (Martin Dürst) wrote:

Wouldn't it be really confusing that for Arrays, #map and #collect are
synonyms, but for Hash, they are different?

It could be confusing, and would also introduce incompatibilities. Also, if the proposal for associate/categorize is accepted, then this collect would be a duplication.

I believe that methods like associate/categorize acting on all Enumerable to produce Hashes would be far more useful (since they don't only act on hashes), without introducing incompatibilities.

#7 Updated by Thomas Sawyer over 1 year ago

It would introduce an incompatibility, but probably not as much as you might think since #map has become the more commonly used method and it is used even less frequently on a Hash.

I think it makes good sense to have a known set of methods that are closed, which is to say they return the same class of object. As matz points out, #select and #reject are already closed. #collect could be made closed without too much trouble since we still have the more widely used #map.

That doesn't get rid of the need for a better Array to Hash conversion method though, which has been discussed in other threads.

#8 Updated by Yusuke Endoh over 1 year ago

  • Status changed from Assigned to Feedback

Yutaka Hara,

We discussed your slide at the developer meeting (7/21).

Matz was positive to the feature itself, but there was no
method name that matz liked. Please find another good name.

Here is a discussion summary:

  • hashmap, maphash
    Matz's most favorite, but not enough to accept.

  • associate
    Not bad, but not enough to accept.

  • mash
    Such a created word is not good.

  • apply, convert, process, graph
    Bad. They suggest something different.

  • morph (Yugui suggested)
    This might be a correct terminology (?), but it is difficult
    for those unfamiliar with category theory.

Yusuke Endoh mame@tsg.ne.jp

#9 Updated by kyo endo over 1 year ago

how about #hmap.

#10 Updated by _ ryenus over 1 year ago

What about #remap

#select and #reject only change the number of k/v pairs and do not change the mapping.

Compared to that, here we want to have certain keys to map to different values, so #remap clearly infers such purpose to me.

Regarding the bang version, i.e., #remap! can be used to modify self instead of returning a new hash.

#11 Updated by David MacMahon over 1 year ago

What about #map! (or are bang methods frowned upon these days)?

#12 Updated by David MacMahon over 1 year ago

Please ignore my previous comment; I see that you want a new Hash rather than replacing the keys/values of the existing Hash. I guess you want a more efficient alternative to:

max_score = Hash[score.map {|k,v| [k, v.max]}]

Since you want to create a new Hash from an existing object, how about a Hash::map factory method:

class Hash
def self.map(other, &block)
other.inject({}) do |h, (k, v)|
newk, newv = *block.call(k, v)
h[newk] = newv
h
end
end
end

Note that "other" doesn't even need to be a Hash (e.g. it could be an Array of two element Arrays). In fact, this:

Hash.map([ [key, value], ... ]) {|*kv| kv}

would be equivalent to:

Hash[ [ [key, value], ... ] ]

Perhaps if Hash::map is not given a block, the behavior could be as if the "{|*kv| kv}" block had been given.

#13 Updated by Thomas Sawyer over 1 year ago

  • mash Such a created word is not good.

I think when no other choices suffice one is left with two options, either created word or long explanatory term, e.g. #mash or #map_hash, respectively.

OTOH, recently I have been looking at new API related to this that uses fluent notation via an Enumerator-like "hashifier", e.g.

enum.hashify.map

This approach allows for other methods to be defined to "hashify" in variant ways.

#14 Updated by Yutaka HARA over 1 year ago

  • Target version changed from 2.0.0 to next minor

#15 Updated by Matthew Kerwin about 1 year ago

I might also suggest the name map_pairs, derived from each_pair. I think it's not incorrect, as the return value from each_pair is the original Hash object, so the return value from map_pairs could also be a Hash object.

Incidentally this paves the way for future possibilities, such as map_keys or map_values (as per each_key and each_value)

#16 Updated by Matthew Kerwin about 1 year ago

phluid61 (Matthew Kerwin) wrote:

I might also suggest the name map_pairs, derived from each_pair. I
think it's not incorrect, as the return value from each_pair is the
original Hash object, so the return value from map_pairs could also be
a Hash object.

Incidentally this paves the way for future possibilities, such as
map_keys or map_values (as per each_key and each_value)

This is related to #7793. I just released a gem that implements Hash#mappairs, #mapkeys, and #map_values. https://rubygems.org/gems/hashmap

Also available in: Atom PDF