Feature #666
closedEnumerable::to_hash
Description
=begin
There are many ways to obtain an array from enumerables (to_a, map, ...).
There is no natural way to obtain a hash from an enumerable (except for Hash[some_array]).
There is a Hash::to_a but no Array::to_hash.
Here is what I would like:
[[:hello, "world"], [:choice, [:red_pill, :blue_pill]]].to_hash ==> {:hello=>"world", :choice=>[:red_pill, :blue_pill]}
(1..3).to_hash{|n| [n, n**2]} ==> {1 => 1, 2 ==> 4, 3 ==> 9}
I propose to add the following Enumerable::to_hash :
module Enumerable
def to_hash
result = {}
self.each do |key, value|
key, value = yield(key, value) if block_given?
result[key] = value
end
result
end
end
Since Hash::to_a returns an array of key-value pairs, I fell it's natural that a block to construct a Hash should return key-value pairs.
This definition has nice symmetric properties: for any Hash h, the following all return a copy of h.
h.to_a.to_hash
h.to_hash{|p| p}
h.to_hash{|k,v| [k,v]}
h.keys.zip(h.values).to_hash
Thank you for your attention,
Marc-Andre Lafortune
=end
        
           Updated by ko1 (Koichi Sasada) almost 17 years ago
          Updated by ko1 (Koichi Sasada) almost 17 years ago
          
          
        
        
      
      - Assignee set to matz (Yukihiro Matsumoto)
=begin
=end
        
           Updated by yugui (Yuki Sonoda) almost 17 years ago
          Updated by yugui (Yuki Sonoda) almost 17 years ago
          
          
        
        
      
      - Target version set to 2.0.0
=begin
=end
        
           Updated by marcandre (Marc-Andre Lafortune) over 16 years ago
          Updated by marcandre (Marc-Andre Lafortune) over 16 years ago
          
          
        
        
      
      =begin
Anyone eagerly waiting for this feature will be interested to read http://redmine.ruby-lang.org/issues/show/1385
=end
        
           Updated by matz (Yukihiro Matsumoto) over 16 years ago
          Updated by matz (Yukihiro Matsumoto) over 16 years ago
          
          
        
        
      
      - Status changed from Open to Rejected
=begin
Enumerable in general does not correspond with mappings, so that I feel Enumerable#to_hash is improper.
=end
        
           Updated by matz (Yukihiro Matsumoto) over 16 years ago
          Updated by matz (Yukihiro Matsumoto) over 16 years ago
          
          
        
        
      
      =begin
Hi,
In message "Re: [ruby-core:23298] Re: Feature #666 	Enumerable::to_hash"
on Fri, 24 Apr 2009 00:08:53 +0900, Marc-Andre Lafortune ruby-core-mailing-list@marc-andre.ca writes:
|
|On Thu, Apr 23, 2009 at 9:55 AM, Michael Fellinger
|m.fellinger@gmail.com wrote:
|
|> Doesn't the new behaviour of Hash::[] solve these cases just as well?
|
|Yes indeed it does, but
|
|1) The new form of Hash[] has yet to be confirmed by Matz (see
|http://redmine.ruby-lang.org/issues/show/1385 ).
Didn't I? I confirm.
|2) It's not as natural as #to_hash. Don't we usually use instance
|methods to convert between types? If you look at conversion between
|basic types, you can convert:
|Numeric <=> String <=> Symbol
|Hash => Array
|All these using instance methods. The only arrow missing is from Array
|back to Hash!
Even though a hash can be represented by an array, there's not always
natural map from Array to Hash.  I am not sure how much to_hash is
useful, when we cannot define what [1,2,3].to_hash should return.
						matz.
=end
        
           Updated by tokland (Arnau Sanchez) over 14 years ago
          Updated by tokland (Arnau Sanchez) over 14 years ago
          
          
        
        
      
      =begin
Hi,
I don't know if it's polite to comment in old closed issues, excuse me if it's not.
I have to say that I wholeheartedly agree with Marc-Andre: the lack of Enumerable-to-Hash conversion is important; in my experience it's an extraordinarily common transformation. Let's see what people usually does (unaware of Facet's Enumerable#mash):
- novice way
h = {}
(1..3).each { |n| h[n] = n**2 }
h
This is just ugly compared with the beautiful, compact, functional code we usually write in Ruby. Moreover, being imperative, it cannot be used in a expression.
- Hash:
Hash[(1..3).map { |n| [n, n**2] }]
Not bad, but it's disappointing in a OOP language to "go back", you'd expect to write from left-to-right as usual and use a method. Moreover, it's less efficient because it needs an intermediate array to be built.
- Enumerable#inject (+update/merge).
(1..3).inject({}) { |hash, n| hash.update(n => 2*n) }
Too verbose, the intent is hidden by the infrastructure.
I think we all agree nothing is clearer than (mash or whatever name):
(1..3).mash { |n| [n, 2*n] }
Finally, answering to Matz prevention:
we cannot define what [1,2,3].to_hash should return
Somehow it's already defined:
Hash[[1,2,3]]
=> {}
Although it would be also ok to raise an exception (as Python does, for example). A mapping has been always represented by a collection of pairs (key, value), all languages with minimal functional capabilities (and Ruby has powerful ones) has such function/method transformation.
=end
        
           Updated by mfn (Markus Fischer) over 14 years ago
          Updated by mfn (Markus Fischer) over 14 years ago
          
          
        
        
      
      Arnau Sanchez wrote:
I don't know if it's polite to comment in old closed issues, excuse me if it's not.
I have to say that I wholeheartedly agree with Marc-Andre: the lack of Enumerable-to-Hash conversion is important; in my experience it's an extraordinarily common transformation. Let's see what people usually does (unaware of Facet's Enumerable#mash):
[...]
Hash[(1..3).map { |n| [n, n**2] }]Not bad, but it's disappointing in a OOP language to "go back", you'd expect to write from left-to-right as usual and use a method. Moreover, it's less efficient because it needs an intermediate array to be built.
Somehow it's already defined:
Hash[[1,2,3]]
=> {}Although it would be also ok to raise an exception (as Python does, for example). A mapping has been always represented by a collection of pairs (key, value), all languages with minimal functional capabilities (and Ruby has powerful ones) has such function/method transformation.
I was about to open a new feature request when I found this, unfortunately rejected, issue.
I'd also love to see Hash[] being available as Array#to_h too; it's just much more convenient. I recently had the urge to sort a hash and would could have been:
some_hash.sort { |a,b| whatever_is_necessary }.to_h
had to be
Hash[ some_hash.sort { |a,b| whatever_is_necessary } ]
- Markus
        
           Updated by marcandre (Marc-Andre Lafortune) over 14 years ago
          Updated by marcandre (Marc-Andre Lafortune) over 14 years ago
          
          
        
        
      
      Thanks for commenting on this old request.
You might want to read the thread [ruby-core:33683] on Akira's
proposal for Enumerable#categorize and my alternative proposal
Enumerable#associate which would act as a more versatile
Enumerable#to_hash.
Your input could have more impact on that thread than on this one.
Hopefully we can come up with a neat functionality for the some future
version of Ruby.
        
           Updated by mfn (Markus Fischer) over 14 years ago
          Updated by mfn (Markus Fischer) over 14 years ago
          
          
        
        
      
      Hi,
On 09.06.2011 20:26, Marc-Andre Lafortune wrote:
You might want to read the thread [ruby-core:33683] on Akira's
proposal for Enumerable#categorize and my alternative proposal
Enumerable#associate which would act as a more versatile
Enumerable#to_hash.Your input could have more impact on that thread than on this one.
Hopefully we can come up with a neat functionality for the some future
version of Ruby.
Thanks for the pointer, very informative. I choose not to add anything
to the other thread, as it seems they goal is a bit different.
My one and only intention is really simple: provide the reverse of
Hash#to_a ("Converts hsh to a nested array of [ key, value ] arrays.") ;
e.g. Array#to_h .
I understood from the other thread much more flexible solutions where
sought, nothing I could aid anything valuable I fear.
I'm just a novice when it comes to Ruby and found a frequent need for
that functionality; maybe it's because of my non-Ruby background and
thus my non-Ruby approach. Likely also that it's not as simple as I
wished this could be, so far Hash[ ... ] was always the solution for me so
class Array ; def to_h ; Hash[ self ]; end; end
worked very well for me.
cheers,
- Markus
        
           Updated by tokland (Arnau Sanchez) over 11 years ago
          Updated by tokland (Arnau Sanchez) over 11 years ago
          
          
        
        
      
      For those interested in this feature, check #7292, Marc-Andre implemented Array#to_h and Enumerable#to_h. It's not as powerful (since it takes no block, you'll usually need to create an intermediate array with "map"), but it's definitely better than Hash[pairs]. Thank you Marc-Andre!