Feature #6669
closedA method like Hash#map but returns hash
Description
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)|
new_k, new_v = *block.call(k, v)
h[new_k] = new_v
h
end
end
end
score = {
taro: [1,3,2],
jiro: [3,5,8,4],
saburo: [2,9]
}
max_score = 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 "hash_map
" is better
(we already have "flat_map
").
Files
Updated by yhara (Yutaka HARA) over 12 years ago
Adding presentation slide for the feature request meeting ([ruby-dev:45708])
Updated by trans (Thomas Sawyer) over 12 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.
Updated by mame (Yusuke Endoh) over 12 years ago
- Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
Received, thank you!
--
Yusuke Endoh mame@tsg.ne.jp
Updated by matz (Yukihiro Matsumoto) over 12 years 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.
Updated by duerst (Martin Dürst) over 12 years 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.
Updated by marcandre (Marc-Andre Lafortune) over 12 years 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.
Updated by trans (Thomas Sawyer) over 12 years 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.
Updated by mame (Yusuke Endoh) over 12 years 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:
-
hash_map, map_hash
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
Updated by merborne (kyo endo) over 12 years ago
how about #hmap.
Updated by ryenus (_ ryenus) over 12 years 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.
Updated by david_macmahon (David MacMahon) over 12 years ago
What about #map! (or are bang methods frowned upon these days)?
Updated by david_macmahon (David MacMahon) over 12 years 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)|
new_k, new_v = *block.call(k, v)
h[new_k] = new_v
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.
Updated by trans (Thomas Sawyer) over 12 years 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.
Updated by yhara (Yutaka HARA) about 12 years ago
- Target version changed from 2.0.0 to 2.6
Updated by phluid61 (Matthew Kerwin) almost 12 years 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
)
Updated by phluid61 (Matthew Kerwin) almost 12 years ago
phluid61 (Matthew Kerwin) wrote:
I might also suggest the name
map_pairs
, derived fromeach_pair
. I
think it's not incorrect, as the return value fromeach_pair
is the
original Hash object, so the return value frommap_pairs
could also be
a Hash object.Incidentally this paves the way for future possibilities, such as
map_keys
ormap_values
(as pereach_key
andeach_value
)
This is related to #7793. I just released a gem that implements Hash#map_pairs, #map_keys, and #map_values. https://rubygems.org/gems/hashmap
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Description updated (diff)
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
- Related to Feature #12512: Import Hash#transform_values and its destructive version from ActiveSupport added
Updated by jeremyevans0 (Jeremy Evans) about 3 years ago
- Status changed from Feedback to Closed
This was implemented by Hash#to_h
taking a block starting in Ruby 2.6.