https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112012-10-30T08:23:47ZRuby Issue Tracking SystemRuby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319342012-10-30T08:23:47ZAnonymous
<ul></ul><p>On Tue, Oct 30, 2012 at 07:23:29AM +0900, nathan.f77 (Nathan Broadbent) wrote:</p>
<blockquote>
<p>Issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a> has been reported by nathan.f77 (Nathan Broadbent).</p>
<hr>
<p>Feature <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a>: Enumerable#to_h proposal<br>
<a href="https://bugs.ruby-lang.org/issues/7241" class="external">https://bugs.ruby-lang.org/issues/7241</a></p>
<p>Author: nathan.f77 (Nathan Broadbent)<br>
Status: Open<br>
Priority: Normal<br>
Assignee:<br>
Category: core<br>
Target version:</p>
<p>I often use the <code>inject</code> method to build a hash, but I always find it annoying when I need to return the hash at the end of the block.<br>
This means that I often write code like:</p>
<pre><code>[1,2,3,4,5].inject({}) {|hash, el| hash[el] = el * 2; hash }
</code></pre>
</blockquote>
<p>1.9.3p194 :001 > [1,2,3,4].each_with_object({}) { |x,o| o[x] = x ** 2 }<br>
=> {1=>1, 2=>4, 3=>9, 4=>16}<br>
1.9.3p194 :002 ></p>
<p>--<br>
Aaron Patterson<br>
<a href="http://tenderlovemaking.com/" class="external">http://tenderlovemaking.com/</a></p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319352012-10-30T08:27:27Zv_krishna (Vijay Ramesh)vijay.krishna.ramesh@gmail.com
<ul></ul><p>Or</p>
<p>1.9.3-p0 :001 > Hash[ [1,2,3,4,5].map{|el| [el, el*2]} ]<br>
=> {1=>2, 2=>4, 3=>6, 4=>8, 5=>10}</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319362012-10-30T08:37:14Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Your idea of to_h is interesting, but it adds too much behavior in one method.<br>
Besides that, since to_s, to_a, to_i etc. are used for implicit conversion, to_h is not a proper name for the method.</p>
<p>Nice try, we will wait for next one.</p>
<p>Matz.</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319372012-10-30T08:37:30Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319492012-10-30T08:53:17Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><p>Thanks! Sorry, I didn't know about each_with_object.</p>
<p>Do you think it would still be worth shortening<br>
<code>each_with_object(Hash.new([])) { ... }</code> to <code>to_h([]) { ... }</code>, and are any<br>
of the other cases worth supporting?</p>
<p>Best,<br>
Nathan</p>
<p>On Tue, Oct 30, 2012 at 12:18 PM, Aaron Patterson<br>
<a href="mailto:tenderlove@ruby-lang.org" class="email">tenderlove@ruby-lang.org</a>wrote:</p>
<blockquote>
<p>On Tue, Oct 30, 2012 at 07:23:29AM +0900, nathan.f77 (Nathan Broadbent)<br>
wrote:</p>
<blockquote>
<p>Issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a> has been reported by nathan.f77 (Nathan Broadbent).</p>
<hr>
<p>Feature <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a>: Enumerable#to_h proposal<br>
<a href="https://bugs.ruby-lang.org/issues/7241" class="external">https://bugs.ruby-lang.org/issues/7241</a></p>
<p>Author: nathan.f77 (Nathan Broadbent)<br>
Status: Open<br>
Priority: Normal<br>
Assignee:<br>
Category: core<br>
Target version:</p>
<p>I often use the <code>inject</code> method to build a hash, but I always find it<br>
annoying when I need to return the hash at the end of the block.<br>
This means that I often write code like:</p>
<pre><code>[1,2,3,4,5].inject({}) {|hash, el| hash[el] = el * 2; hash }
</code></pre>
</blockquote>
<p>1.9.3p194 :001 > [1,2,3,4].each_with_object({}) { |x,o| o[x] = x ** 2 }<br>
=> {1=>1, 2=>4, 3=>9, 4=>16}<br>
1.9.3p194 :002 ></p>
<p>--<br>
Aaron Patterson<br>
<a href="http://tenderlovemaking.com/" class="external">http://tenderlovemaking.com/</a></p>
</blockquote> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319502012-10-30T08:53:18Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><p>OK, no problem! Thanks for your response!</p>
<p>A bit unrelated, but is it strange that each_with_object and inject have a<br>
different order for the block params?</p>
<pre><code> [1,2,3].inject({}) {|obj, el| obj[el] = el * 2; obj } #=> {1=>2,
</code></pre>
<p>2=>4, 3=>6}</p>
<pre><code> [1,2,3].each_with_object({}) {|obj, el| obj[el] = el * 2 } #=>
</code></pre>
<p>NoMethodError: undefined method `*' for {}:Hash</p>
<pre><code> [1,2,3].each_with_object({}) {|el, obj| obj[el] = el * 2 } #=> {1=>2,
</code></pre>
<p>2=>4, 3=>6}</p>
<p>On Tue, Oct 30, 2012 at 12:37 PM, matz (Yukihiro Matsumoto) <<br>
<a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a>> wrote:</p>
<blockquote>
<p>Issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a> has been updated by matz (Yukihiro Matsumoto).</p>
<p>Status changed from Open to Rejected</p>
<hr>
<p>Feature <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a>: Enumerable#to_h proposal<br>
<a href="https://bugs.ruby-lang.org/issues/7241#change-31937" class="external">https://bugs.ruby-lang.org/issues/7241#change-31937</a></p>
<p>Author: nathan.f77 (Nathan Broadbent)<br>
Status: Rejected<br>
Priority: Normal<br>
Assignee:<br>
Category: core<br>
Target version:</p>
<p>I often use the <code>inject</code> method to build a hash, but I always find it<br>
annoying when I need to return the hash at the end of the block.<br>
This means that I often write code like:</p>
<pre><code>[1,2,3,4,5].inject({}) {|hash, el| hash[el] = el * 2; hash }
</code></pre>
<p>I'm proposing an <code>Enumerable#to_h</code> method that would let me write:</p>
<pre><code>[1,2,3,4,5].to_h {|h, el| h[el] = el * 2 }
</code></pre>
<p>I saw the proposal at <a href="http://bugs.ruby-lang.org/issues/666" class="external">http://bugs.ruby-lang.org/issues/666</a>, but I would<br>
not be in favor of his implementation.<br>
I believe the implementation should be similar to <code>inject</code>, so that the<br>
hash object and next element are passed to the block. The main difference<br>
to the <code>inject</code> method is that we would be modifying the hash in place,<br>
instead of relying on the block's return value.</p>
<p>As well as providing support for the case above, I have also considered<br>
other cases where the <code>to_h</code> method would be useful.<br>
I thought it would be useful if symmetry were provided for the <code>Hash#to_a</code><br>
method, such that:</p>
<pre><code>hash.to_a.to_h == hash # => true
</code></pre>
<p>(See example 2)</p>
<p>I've allowed developers to provide a symbol instead of a block, so that<br>
each element in the collection will be passed to that named method. (See<br>
example 3)</p>
<p>Finally, hashes can be given a default value, or a Proc that returns the<br>
default value. (See examples 4 & 5)</p>
<p>Heres an example implementation that I would be happy to rewrite in C if<br>
necessary:</p>
<pre><code>module Enumerable
def to_h(default_or_sym = nil)
if block_given?
hash = if Proc === default_or_sym
Hash.new(&default_or_sym)
else
Hash.new(default_or_sym)
end
self.each do |el|
yield hash, el
end
elsif !default_or_sym.nil?
hash = {}
self.each do |el|
hash[el] = el.send(default_or_sym)
end
else
return Hash[*self.to_a.flatten(1)]
end
hash
end
end
</code></pre>
<a name="Examples"></a>
<h2 >Examples<a href="#Examples" class="wiki-anchor">¶</a></h2>
<a name="1-Build-a-hash-from-array-elements"></a>
<h1 >1) Build a hash from array elements<a href="#1-Build-a-hash-from-array-elements" class="wiki-anchor">¶</a></h1>
<pre><code>[1,2,3,4,5].to_h {|h, el| h[el] = el * 2 }
</code></pre>
<p>=> {1=>2, 2=>4, 3=>6, 4=>8, 5=>10}</p>
<a name="2-Provides-symmetry-for-Hashto_a-ie-you-can-call-hashto_ato_h"></a>
<h1 >2) Provides symmetry for Hash.to_a (i.e. you can call hash.to_a.to_h)<a href="#2-Provides-symmetry-for-Hashto_a-ie-you-can-call-hashto_ato_h" class="wiki-anchor">¶</a></h1>
<pre><code>[[1, 2], [3, 4], [5, 6]].to_h
</code></pre>
<p>=> {1=>2, 3=>4, 5=>6}</p>
<a name="3-Build-a-hash-by-calling-a-method-on-each-array-element"></a>
<h1 >3) Build a hash by calling a method on each array element<a href="#3-Build-a-hash-by-calling-a-method-on-each-array-element" class="wiki-anchor">¶</a></h1>
<pre><code>["String", "Another String"].to_h(:size)
</code></pre>
<p>=> {"String"=>6, "Another String"=>14}</p>
<a name="4-Hash-with-default-value"></a>
<h1 >4) Hash with default value<a href="#4-Hash-with-default-value" class="wiki-anchor">¶</a></h1>
<pre><code>[4,5,6,5].to_h(0) {|h, el| h[el] += el }
</code></pre>
<p>=> {4=>4, 5=>10, 6=>6}</p>
<a name="5-Hash-with-default-value-returned-from-Proc"></a>
<h1 >5) Hash with default value returned from Proc<a href="#5-Hash-with-default-value-returned-from-Proc" class="wiki-anchor">¶</a></h1>
<pre><code>default_proc = -> hash, key { hash[key] = "go fish: #{key}" }
[4,5,6].to_h(default_proc) {|h, el| h[el].upcase! }
</code></pre>
<p>=> {4=>"GO FISH: 4", 5=>"GO FISH: 5", 6=>"GO FISH: 6"}</p>
<p>Thanks for your time, and please let me know your thoughts!</p>
<p>Best,<br>
Nathan Broadbent</p>
<p>--<br>
<a href="http://bugs.ruby-lang.org/" class="external">http://bugs.ruby-lang.org/</a></p>
</blockquote> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=319732012-10-30T19:58:32Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<ul></ul><p>Maybe .hash_map? each_with_object is a too long name for a very common needed method. Many have asked for a method like it (including me) because they couldn't find "each_with_object" and they ended up learning here after asking for such a method.</p>
<p>Maybe "hash_map" could be a better name for this.</p>
<p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>Your idea of to_h is interesting, but it adds too much behavior in one method.<br>
Besides that, since to_s, to_a, to_i etc. are used for implicit conversion, to_h is not a proper name for the method.</p>
<p>Nice try, we will wait for next one.</p>
<p>Matz.</p>
</blockquote> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=320402012-10-31T03:29:15ZAnonymous
<ul></ul><p>On Tue, Oct 30, 2012 at 07:58:33PM +0900, rosenfeld (Rodrigo Rosenfeld Rosas) wrote:</p>
<blockquote>
<p>Issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a> has been updated by rosenfeld (Rodrigo Rosenfeld Rosas).</p>
<p>Maybe .hash_map? each_with_object is a too long name for a very common needed method. Many have asked for a method like it (including me) because they couldn't find "each_with_object" and they ended up learning here after asking for such a method.</p>
<p>Maybe "hash_map" could be a better name for this.</p>
</blockquote>
<p><code>each_with_object</code> isn't specific to hashes, and isn't doing list<br>
translation like <code>map</code> does.</p>
<p>IOW, it sounds perfect for ActiveSupport. ;-)</p>
<p>--<br>
Aaron Patterson<br>
<a href="http://tenderlovemaking.com/" class="external">http://tenderlovemaking.com/</a></p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=320452012-10-31T06:23:17Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<ul></ul><p>Em 30-10-2012 16:23, Aaron Patterson escreveu:</p>
<blockquote>
<p>On Tue, Oct 30, 2012 at 07:58:33PM +0900, rosenfeld (Rodrigo Rosenfeld Rosas) wrote:</p>
<blockquote>
<p>Issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a> has been updated by rosenfeld (Rodrigo Rosenfeld Rosas).</p>
<p>Maybe .hash_map? each_with_object is a too long name for a very common needed method. Many have asked for a method like it (including me) because they couldn't find "each_with_object" and they ended up learning here after asking for such a method.</p>
<p>Maybe "hash_map" could be a better name for this.<br>
<code>each_with_object</code> isn't specific to hashes, and isn't doing list<br>
translation like <code>map</code> does.</p>
</blockquote>
<p>IOW, it sounds perfect for ActiveSupport. ;-)</p>
</blockquote>
<p>I often have this requirement and I guess others have it as well. There<br>
are two problems with each_with_object in my opinion:</p>
<p>1 - you can't find it easily in the docs when you're looking for some<br>
way to "inject" a Hash without worrying about the result of the block;<br>
hash_map would be easier to find in the docs for newcomers (to<br>
each_with_object I mean, like I was less then an year ago if I remember<br>
correctly);<br>
2 - it is a too long name. See examples below:</p>
<p>hash =<br>
a_long_array_name_as_I_usually_use_for_my_variables.each_with_object({}){|(name,<br>
url), h| h[name] = url }<br>
h = {}; a_long_array_name_as_I_usually_use_for_my_variables.each{|(name,<br>
url)| h[name] = url }; hash = h</p>
<p>Often in my methods I don't really need that extra (; hash = h) so it is<br>
usually much shorter when I don't use each_with_object.</p>
<p>With proposed method:</p>
<p>hash = a_long_array_name_as_I_usually_use_for_my_variables.hash_map{|h,<br>
(name, url)| h[name] = url }</p>
<p>Notice that I changed the order of the arguments for the block. It makes<br>
more sense to me this way, just like inject.</p>
<p>I know this is subjective but I find the last example better to read ;)</p>
<p>Cheers,<br>
Rodrigo.</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321332012-11-01T11:53:10Ztrans (Thomas Sawyer)
<ul></ul><p>Almost no one uses #each_with_object as it is. #each_with_hash is hardly<br>
better. We need a short method name. Moreover I don't think this method's<br>
behavior is really the best approach to the real use case.</p>
<p>On Wed, Oct 31, 2012 at 7:07 PM, Nathan Broadbent <a href="mailto:nathan.f77@gmail.com" class="email">nathan.f77@gmail.com</a>wrote:</p>
<blockquote>
<p>Hi everyone,</p>
<p>Please see the pull request that I've opened on Rails ActiveSupport, to<br>
add an <code>each_with_hash</code> method: <a href="https://github.com/rails/rails/pull/8088" class="external">https://github.com/rails/rails/pull/8088</a></p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a>: Do you think this <code>each_with_hash</code> implementation could be added to<br>
Ruby, or is it better as a Rails ActiveSupport extension?</p>
<p>Best,<br>
Nathan</p>
</blockquote>
<p>--<br>
Sorry, says the barman, we don't serve neutrinos. A neutrino walks into a<br>
bar.</p>
<p>Trans <a href="mailto:transfire@gmail.com" class="email">transfire@gmail.com</a><br>
7r4n5.com <a href="http://7r4n5.com" class="external">http://7r4n5.com</a></p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321342012-11-01T12:23:36Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><blockquote>
<p>Almost no one uses #each_with_object as it is. #each_with_hash is hardly<br>
better. We need a short method name. Moreover I don't think this method's<br>
behavior is really the best approach to the real use case.</p>
</blockquote>
<p>It's true that each_with_object doesn't seem to be used too much, but when<br>
it is used, the object is usually a hash (for 90% of the cases in Rails, at<br>
least.)</p>
<p>I think that each_with_hash should be provided for when you want to map an<br>
enumerable onto a Hash, but I think that there should also be a 'to_h'<br>
method on Array for when you just want to <em>convert</em> an Array into a hash.</p>
<p>I think 'to_h' would be most useful if it supported the behaviour of both<br>
<code>Hash[ arr ]</code>, and 'Hash[ *arr ]'. I'm on my phone at the moment, but<br>
here's how I could see that working:</p>
<p>def to_h<br>
if self.all? {|el| el.respond_to? :each && el.size == 2 }<br>
Hash[self]<br>
else<br>
Hash[*self]<br>
end<br>
end</p>
<p>We could just let Hash[] handle any invalid input.</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321352012-11-01T12:23:36ZAnonymous
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="https://blade.ruby-lang.org/ruby-core/48690">[ruby-core:48690]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a>] Enumerable#to_h proposal"<br>
on Thu, 1 Nov 2012 08:07:11 +0900, Nathan Broadbent <a href="mailto:nathan.f77@gmail.com" class="email">nathan.f77@gmail.com</a> writes:</p>
<p>|@matz: Do you think this <code>each_with_hash</code> implementation could be added to<br>
|Ruby, or is it better as a Rails ActiveSupport extension?</p>
<p>I think it should go in to ActiveSupport first.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321362012-11-01T12:29:19Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><blockquote>
<p>I think it should go in to ActiveSupport first.</p>
<pre><code> matz.
</code></pre>
</blockquote>
<p>Thanks for your reply! The pull request has just been rejected on<br>
ActiveSupport, so I guess that's the end of this discussion :)</p>
<p>Thank you for Ruby, by the way, it's a beautiful language!</p>
<p>Best,<br>
Nathan</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321462012-11-01T17:10:04Zalexeymuranov (Alexey Muranov)
<ul></ul><p>Just in case, here is some relevant discussion on StackOverflow with benchmarks:</p>
<p><a href="http://stackoverflow.com/questions/3230863/ruby-rails-inject-on-hashes-good-style" class="external">http://stackoverflow.com/questions/3230863/ruby-rails-inject-on-hashes-good-style</a></p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321472012-11-01T17:49:11Ztrans (Thomas Sawyer)
<ul></ul><p>=begin<br>
I wouldn't say it is over. See <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#categorize (Rejected)" href="https://bugs.ruby-lang.org/issues/4151">#4151</a>.</p>
<p>I still like:</p>
<p>module Enumerable<br>
def each_with(x={})<br>
each{ |e| yield(x,e) }<br>
x<br>
end<br>
end</p>
<p>Is #each_with a better name?<br>
=end</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=321512012-11-01T19:23:16Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><blockquote>
<p>I wouldn't say it is over. See <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#categorize (Rejected)" href="https://bugs.ruby-lang.org/issues/4151">#4151</a>. ...</p>
</blockquote>
<p>Is #each_with a better name?</p>
<blockquote>
</blockquote>
<p>Has anyone suggested <code>map_to</code>? I think <code>map_to</code> has a clearer intention<br>
than <code>each_with</code>, because you're mapping the collection onto something, and<br>
then returning it.<br>
I don't really like the <code>each</code> part of <code>each_with_object</code>, because<br>
<code>array.each</code> just returns the array. Since we usually use <code>each</code> to<br>
iterate, and <code>map</code> to build an array, I think <code>map_to(<object>)</code> might make<br>
sense.</p>
<p>How does this look:</p>
<p>[1, 2, 3].map_to({}) { |e, hash| hash[e] = e ** 2 }</p>
<p>I'd also propose a <code>map_to_hash</code> method. It's longer than <code>map_to({})</code>, but<br>
I think it's nicer to read:</p>
<p>[1, 2, 3].map_to_hash { |e, hash| hash[e] = e ** 2 }</p>
<p><code>map_to_hash(0)</code> would also be nicer than <code>map_to(Hash.new(0))</code>.</p>
<p>What do you think?</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=327552012-11-11T00:47:14Zjballanc (Joshua Ballanco)jballanc@gmail.com
<ul></ul><p>=begin<br>
Clojure has a function (({into})) that might fit the bill. An equivalent Ruby implementation might look something like the following:</p>
<pre><code>class Hash
alias :<< :merge!
end
module Enumerable
def into(coll)
coll = coll.dup
each do |elem|
coll << yield(elem)
end
coll
end
end
chars = (97..107).into({}) { |i| { i => i.chr } }
p chars
require 'prime'
prime_chars = chars.into([]) { |k, v| k.prime? ? v : nil }
p prime_chars.compact
char_string = chars.into("") { |k, v| "#{k}=>#{v}, " }
p char_string
</code></pre>
<p>=end</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=327712012-11-11T17:59:22Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<ul></ul><p>On 2012/11/11 0:47, jballanc (Joshua Ballanco) wrote:</p>
<blockquote>
<p>Issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a> has been updated by jballanc (Joshua Ballanco).</p>
<p>=begin<br>
Clojure has a function (({into})) that might fit the bill.</p>
</blockquote>
<p>This indeed looks very promising.</p>
<blockquote>
<p>An equivalent Ruby implementation might look something like the following:</p>
<pre><code> class Hash
alias :<< :merge!
end
</code></pre>
</blockquote>
<p>I might be wrong, but my guess is that constructing lots of<br>
one-key/value hashes isn't very efficient. Two-element arrays should be<br>
quite a bit more efficient. So we could define this as follows (in the<br>
end in C, but here just in Ruby):</p>
<p>class Hash<br>
def << (other)<br>
case other.class<br>
when Array<br>
store(other[0], other[1])<br>
when Hash<br>
merge! other<br>
end<br>
self<br>
end<br>
end</p>
<p>(some additional tweaks may be needed for Array-like and Hash-like objects).</p>
<blockquote>
<pre><code> module Enumerable
def into(coll)
coll = coll.dup
each do |elem|
coll<< yield(elem)
end
coll
end
end
chars = (97..107).into({}) { |i| { i => i.chr } }
p chars
require 'prime'
prime_chars = chars.into([]) { |k, v| k.prime? ? v : nil }
p prime_chars.compact
</code></pre>
</blockquote>
<p>It would be great to have a version that avoided "compact". Or maybe<br>
only that version would be okay? This would use "concat" instead of<br>
merge! (with Hash#concat an alias for Hash#merge!). Because neither<br>
Hashes nor Strings can be nested, there would actually not be any<br>
difference for those, but for Array, the preceeding code could be<br>
simplified to:</p>
<pre><code> require 'prime'
prime_chars = chars.into___([]) { |k, v| k.prime? ? [v] : [] }
</code></pre>
<p>I often want a "collect" method where I'm not forced to collect exactly<br>
one item per item of the original collection. If collect weren't an<br>
alias to map, I think it would even make a lot of sense to use the word<br>
"collect" for this (map: one-to-one, collect: one-to-many).</p>
<p>Regards, Martin.</p>
<blockquote>
<pre><code> char_string = chars.into("") { |k, v| "#{k}=>#{v}, " }
p char_string
</code></pre>
<p>=end</p>
<hr>
<p>Feature <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://bugs.ruby-lang.org/issues/7241">#7241</a>: Enumerable#to_h proposal<br>
<a href="https://bugs.ruby-lang.org/issues/7241#change-32755" class="external">https://bugs.ruby-lang.org/issues/7241#change-32755</a></p>
<p>Author: nathan.f77 (Nathan Broadbent)<br>
Status: Rejected<br>
Priority: Normal<br>
Assignee:<br>
Category: core<br>
Target version:</p>
<p>I often use the <code>inject</code> method to build a hash, but I always find it annoying when I need to return the hash at the end of the block.<br>
This means that I often write code like:</p>
<pre><code> [1,2,3,4,5].inject({}) {|hash, el| hash[el] = el * 2; hash }
</code></pre>
<p>I'm proposing an <code>Enumerable#to_h</code> method that would let me write:</p>
<pre><code> [1,2,3,4,5].to_h {|h, el| h[el] = el * 2 }
</code></pre>
<p>I saw the proposal at <a href="http://bugs.ruby-lang.org/issues/666" class="external">http://bugs.ruby-lang.org/issues/666</a>, but I would not be in favor of his implementation.<br>
I believe the implementation should be similar to <code>inject</code>, so that the hash object and next element are passed to the block. The main difference to the <code>inject</code> method is that we would be modifying the hash in place, instead of relying on the block's return value.</p>
<p>As well as providing support for the case above, I have also considered other cases where the <code>to_h</code> method would be useful.<br>
I thought it would be useful if symmetry were provided for the <code>Hash#to_a</code> method, such that:</p>
<pre><code> hash.to_a.to_h == hash # => true
</code></pre>
<p>(See example 2)</p>
<p>I've allowed developers to provide a symbol instead of a block, so that each element in the collection will be passed to that named method. (See example 3)</p>
<p>Finally, hashes can be given a default value, or a Proc that returns the default value. (See examples 4& 5)</p>
<p>Heres an example implementation that I would be happy to rewrite in C if necessary:</p>
<pre><code> module Enumerable
def to_h(default_or_sym = nil)
if block_given?
hash = if Proc === default_or_sym
Hash.new(&default_or_sym)
else
Hash.new(default_or_sym)
end
self.each do |el|
yield hash, el
end
elsif !default_or_sym.nil?
hash = {}
self.each do |el|
hash[el] = el.send(default_or_sym)
end
else
return Hash[*self.to_a.flatten(1)]
end
hash
end
end
</code></pre>
<a name="Examples"></a>
<h2 >Examples<a href="#Examples" class="wiki-anchor">¶</a></h2>
<a name="1-Build-a-hash-from-array-elements"></a>
<h1 >1) Build a hash from array elements<a href="#1-Build-a-hash-from-array-elements" class="wiki-anchor">¶</a></h1>
<pre><code> [1,2,3,4,5].to_h {|h, el| h[el] = el * 2 }
</code></pre>
<p>=> {1=>2, 2=>4, 3=>6, 4=>8, 5=>10}</p>
<a name="2-Provides-symmetry-for-Hashto_a-ie-you-can-call-hashto_ato_h"></a>
<h1 >2) Provides symmetry for Hash.to_a (i.e. you can call hash.to_a.to_h)<a href="#2-Provides-symmetry-for-Hashto_a-ie-you-can-call-hashto_ato_h" class="wiki-anchor">¶</a></h1>
<pre><code> [[1, 2], [3, 4], [5, 6]].to_h
</code></pre>
<p>=> {1=>2, 3=>4, 5=>6}</p>
<a name="3-Build-a-hash-by-calling-a-method-on-each-array-element"></a>
<h1 >3) Build a hash by calling a method on each array element<a href="#3-Build-a-hash-by-calling-a-method-on-each-array-element" class="wiki-anchor">¶</a></h1>
<pre><code> ["String", "Another String"].to_h(:size)
</code></pre>
<p>=> {"String"=>6, "Another String"=>14}</p>
<a name="4-Hash-with-default-value"></a>
<h1 >4) Hash with default value<a href="#4-Hash-with-default-value" class="wiki-anchor">¶</a></h1>
<pre><code> [4,5,6,5].to_h(0) {|h, el| h[el] += el }
</code></pre>
<p>=> {4=>4, 5=>10, 6=>6}</p>
<a name="5-Hash-with-default-value-returned-from-Proc"></a>
<h1 >5) Hash with default value returned from Proc<a href="#5-Hash-with-default-value-returned-from-Proc" class="wiki-anchor">¶</a></h1>
<pre><code> default_proc = -> hash, key { hash[key] = "go fish: #{key}" }
[4,5,6].to_h(default_proc) {|h, el| h[el].upcase! }
</code></pre>
<p>=> {4=>"GO FISH: 4", 5=>"GO FISH: 5", 6=>"GO FISH: 6"}</p>
<p>Thanks for your time, and please let me know your thoughts!</p>
<p>Best,<br>
Nathan Broadbent</p>
</blockquote> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=327742012-11-11T18:53:19Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><blockquote>
<p>Clojure has a function (({into})) that might fit the bill.</p>
<blockquote>
</blockquote>
<p>This indeed looks very promising.</p>
</blockquote>
<p>I like the sound of 'into', but am not sure about appending results with<br>
the '<<' operator. If Hash had '<<' and '+' aliases for 'update' and<br>
'merge' (respectively), we might as well give 'map' an optional argument,<br>
and call:</p>
<pre><code> [1,2,3].map({}) {|i| { i => i ** 2 } }
</code></pre>
<p>And if Hash#update accepted a two-element array, we could do:</p>
<pre><code> [1,2,3].map({}) {|i| [i, i ** 2] }
</code></pre>
<p>So I like the 'into' name, but I think it would be more useful as an alias<br>
for 'each_with_object', instead of just 'map' with an argument for the base<br>
object.</p>
<blockquote>
<p>I often want a "collect" method where I'm not forced to collect exactly<br>
one item per item of the original collection. If collect weren't an alias<br>
to map, I think it would even make a lot of sense to use the word "collect"<br>
for this (map: one-to-one, collect: one-to-many).</p>
</blockquote>
<p>Ruby has a 'flat_map' method (aliased as 'collect_concat') that flattens<br>
the first level of a returned array, so you can append multiple results,<br>
and don't need to use compact. See<br>
<a href="http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-flat_map" class="external">http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-flat_map</a></p>
<pre><code> [1,nil,2].flat_map {|i| i ? [i] : [] } #=> [1, 2]
</code></pre>
<p>Best,<br>
Nathan</p> Ruby master - Feature #7241: Enumerable#to_h proposalhttps://bugs.ruby-lang.org/issues/7241?journal_id=328142012-11-12T22:07:14Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<ul></ul><p>I like "into". But I'd vote it to be an alias to "each_of_object" as I even prefer "into" instead of "each_with" or "map_with". I'd also vote for the order of the closure arguments to be changed.</p>
<p>I read "doubles = numbers.into({}){|h, n| h[n] = 2 * n }" as "assign to double the numbers into a hash indexed by each number having the double as value".</p>