https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112012-11-07T04:56:20ZRuby Issue Tracking SystemRuby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325142012-11-07T04:56:20Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><p>I agree, Enumerable#to_h would make sense and be quite useful.</p>
<p>(1..3).to_h would be a special case for the Range class, because [1, 2, 3].to_h should raise an exception.</p>
<p>Here's an example in Ruby:</p>
<p>module Enumerable<br>
def to_h<br>
hash = {}<br>
each_with_index do |el, i|<br>
raise TypeError, "(at index #{i}) Element is not an Array" unless Array === el<br>
raise IndexError, "(at index #{i}) Array has more than 2 elements" if el.size > 2<br>
hash[el[0]] = el[1]<br>
end<br>
hash<br>
end<br>
end</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325232012-11-07T08:44:11Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Feedback</i></li><li><strong>Priority</strong> changed from <i>Normal</i> to <i>3</i></li></ul><p>So what's the difference from rejected <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://redmine.ruby-lang.org/issues/7241">#7241</a>?</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325252012-11-07T10:05:55Znathan.f77 (Nathan Broadbent)nathan.f77@gmail.com
<ul></ul><blockquote>
<p>So what's the difference from rejected <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://redmine.ruby-lang.org/issues/7241">#7241</a>?</p>
</blockquote>
<p>The main difference is that <code>to_h</code> wouldn't take a block or any arguments. It would be a simple conversion from Enumerable to Hash, and would only support a collection of arrays containing a maximum of 2 elements.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325322012-11-07T12:31:19Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Feedback</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>matz (Yukihiro Matsumoto)</i></li></ul><p>Use the traditional Hash[] in 2.0.0. I'm moving this ticket into the feature tracker.</p>
<p>p Hash[ [[:name, 'Joe Smith'], [:age, 42]] ]<br>
#=> {name: 'Joe Smith', age: 42}</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325332012-11-07T12:31:26Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Target version</strong> set to <i>2.6</i></li></ul> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325352012-11-07T12:48:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>So what's the difference from rejected <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://redmine.ruby-lang.org/issues/7241">#7241</a>?</p>
</blockquote>
<p>As Nathan said, <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#to_h proposal (Rejected)" href="https://redmine.ruby-lang.org/issues/7241">#7241</a> (and <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable::to_hash (Rejected)" href="https://redmine.ruby-lang.org/issues/666">#666</a>) accept a block and are therefore more related to the more complex categorize/associate/... <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#categorize (Rejected)" href="https://redmine.ruby-lang.org/issues/4151">#4151</a>.</p>
<p>The implementation for <code>to_h</code> would be as simple conceptually as possible. It would be equivalent to:</p>
<p>module Enumerable<br>
def to_h<br>
result = {}<br>
each do |key, value|<br>
result[key] = value<br>
end<br>
result<br>
end<br>
end</p>
<p>I believe this is the simplest definition one can think of. It doesn't try to do much, nor is it too strict (in the same way that "two".to_i returns 0).</p>
<p>mame (Yusuke Endoh) wrote:</p>
<blockquote>
<p>Use the traditional Hash[] in 2.0.0.</p>
</blockquote>
<p>Indeed, Hash[] can be used instead, except it's really really ugly.</p>
<p>I can't think of any other global method we use like this that should be an instance method. It's very natural to transform data into a hashes, but instead of chaining the transformations we have to reverse the flow for this step. E.g. <code>source.map{...}.to_h.merge(...)</code> reads naturally, but <code>Hash[source.map{...}].merge(...)</code> doesn't.</p>
<p>The only other example of SomeClass.[] I can think of is for Set. In that case, it's understandable as Set doesn't have a dedicated creation syntax, so <code>Set[1, 2, 3]</code> has its charms. Are there other cases, besides Hash[]?</p>
<blockquote>
<p>I'm moving this ticket into the feature tracker.<br>
Didn't I create it as a feature request?</p>
</blockquote> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325362012-11-07T13:01:02Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>marcandre (Marc-Andre Lafortune) wrote:</p>
<blockquote>
<blockquote>
<p>I'm moving this ticket into the feature tracker.<br>
Didn't I create it as a feature request?</p>
</blockquote>
</blockquote>
<p>Oops, I was mistaken. I just set the target to next minor. Sorry.</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325762012-11-08T03:01:47Zprijutme4ty (Ilya Vorontsov)prijutme4ty@gmail.com
<ul></ul><p>Hash.[] is one of most disastrous ruby methods, IMHO. Since we don't have hash_map it's common to write smth like<br>
hsh = Hash[ hsh.map{|k,v| [k.to_sym, v.to_f]} ]<br>
In some more complicated cases it makes any programmer, who looks at code, cry.<br>
Actually I'd prefer to have both methods Enumerable#to_h and Hash#hash_map ( <a href="http://bugs.ruby-lang.org/issues/6669" class="external">http://bugs.ruby-lang.org/issues/6669</a> )<br>
Programmers anyway use analogues for this method, so it'd be a way to standardize their code. As marcandre said #to_i also isn't ideal but is very useful and each programmer understand it the same way.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325862012-11-08T03:58:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><blockquote>
<p>Actually I'd prefer to have both methods Enumerable#to_h and Hash#hash_map ( <a href="http://bugs.ruby-lang.org/issues/6669" class="external">http://bugs.ruby-lang.org/issues/6669</a> )</p>
</blockquote>
<p>I'm a strong supporter for different <code>hash_map/associate/categorize</code>, but let's not discuss these here please, they have their own tickets (<a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Enumerable#categorize (Rejected)" href="https://redmine.ruby-lang.org/issues/4151">#4151</a> & <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: A method like Hash#map but returns hash (Closed)" href="https://redmine.ruby-lang.org/issues/6669">#6669</a>).</p>
<p>This request is not meant to be a replacement for those requests. It is a small step, the simplest method to explicitly convert an Enumerable to a Hash.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=325972012-11-08T06:32:02Zbitsweat (Jeremy Daer)jeremydaer@gmail.com
<ul></ul><p>+1 to this.</p>
<p>I didn't like it at first because <code>#to_h</code> means coercion to me, and it doesn't make sense to coerce an Enumerable to a Hash. However, <code>Array#to_h</code> does seem like a good fit. Coerce this array of associated key/value pairs to a hash. Deal with edge cases in the same was as <code>Hash[]</code>.</p>
<p>I'd immediately change a lot of code to use this if it was available. Ending a chain of enumerable methods with <code>.to_h</code> is much nicer than "going back" to wrap it in <code>Hash[]</code>.</p>
<p>(Perhaps <code>Enumerable#to_h</code> could remain as a shortcut for <code>to_a.to_h</code>?)</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=372212013-03-01T21:50:38Zjipiboily (Jean-Philippe Boily)j@jipi.ca
<ul></ul><p>+1</p>
<p>This would just feel right and natural to me.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=375692013-03-13T20:05:07Znewmen (Gleb Averchuk)altermn@gmail.com
<ul></ul><p>I think this is very cool feature, because I'm tired of writing something like this:</p>
<p>some_hash = Hash[some_hash.map { |k, v| [k, (v * scale).to_i] }]</p>
<p>)=</p>
<p>P.S.<br>
In actual fact is not very tired. :)<br>
And it may have a more elegant way that will change the Hash by using .map method.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=375762013-03-14T02:12:09Zdrbrain (Eric Hodel)drbrain@segment7.net
<ul></ul><p>=begin<br>
There is a potential for a security exploit with Enumerable#to_h:</p>
<p>user_input = %w[rm -rf /]<br>
system ['ls', '-l'], *user_input</p>
<p>With system, the first argument is used as the environment if it can be converted to a Hash. With user input to system this may lead to arbitrary code execution.<br>
=end</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=375772013-03-14T02:23:42Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>drbrain (Eric Hodel) wrote:</p>
<blockquote>
<p>There is a potential for a security exploit with Enumerable#to_h:</p>
<p>user_input = %w[rm -rf /]<br>
system ['ls', '-l'], *user_input</p>
<p>With system, the first argument is used as the environment if it can be converted to a Hash. With user input to system this may lead to arbitrary code execution.</p>
</blockquote>
<p>I think you are confusing <code>to_h</code> (explicit conversion) with <code>to_hash</code> (implicit conversion). <code>system</code> calls rb_check_hash_type which will attempt to call <code>to_hash</code> but will <em>not</em> send <code>to_h</code> on its argument.</p>
<p>So no, there is no such potential security risk here.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=382352013-04-05T01:51:39Zrogerdpack (Roger Pack)rogerpack2005@gmail.com
<ul></ul><p>+1 from me. Sometimes after converting from an array to a hash I want to "convert back" to a hash and inevitably I reach for "to_h" just to discover it's not there.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=406442013-07-24T18:34:12Zalexeymuranov (Alexey Muranov)
<ul></ul><p>I have stumbled upon a need for a method like this, to chain transformations of a hash and get a hash as a result. Just a quick thought (please tell me if i have overlooked something): it seems to me that other "#to_?" methods are applicable to all or almost all instances of a class, whereas here the method would be applicable only to a special kind of arrays: the ones consisting of key-value pairs.</p>
<p>Maybe there is no need to call it "#to_h", and it is better to reserve "#to_h" for some operation applicable to all arrays? Maybe the proposed method can be called something like "#as_hash" , "#as_h", or a different name?</p>
<p>[[1, 2], [3,4]].as_hash # => {1=>2, 3=> 4}</p>
<hr>
<p>To generalize this, maybe "as_?" methods can be defined as left inverses of "to_?" methods (in method chaining, they should probably be called right inverses):</p>
<p>{1=>2, 3=>4}.to_a.as_hash # => {1=>2, 3=>4}<br>
{1=>2, 3=>4}.to_s.as_hash # => {1=>2, 3=>4}<br>
"{1=>2, 3=>4}".as_hash # => {1=>2, 3=>4}</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=406532013-07-25T06:28:59Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>alexeymuranov (Alexey Muranov) wrote:</p>
<blockquote>
<p>it seems to me that other "#to_?" methods are applicable to all or almost all instances of a class</p>
</blockquote>
<p>String#to_i is not meaningful on most strings.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=406862013-07-26T17:41:43Zalexeymuranov (Alexey Muranov)
<ul></ul><p>Yes, thanks, i forgot. Then "to_h" would be fine with me.</p>
<p>In fact, for me it would be enough to have a method like "yield_self" <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Object#yield_self (Closed)" href="https://redmine.ruby-lang.org/issues/6721">#6721</a>, then i would do "array.yield_self {|a| Hash[a] }"</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=407062013-07-27T15:07:24Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Feedback</i></li></ul><p>the name 'to_h' is OK, simpler behavior is preferable compared with the past proposals.</p>
<p>But I am not sure the following simple implementation works OK, e.g. what if an element is a object, or number, or anything not two-element array.</p>
<p>module Enumerable<br>
def to_h<br>
result = {}<br>
each do |key, value|<br>
result[key] = value<br>
end<br>
result<br>
end<br>
end</p>
<p>Matz.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=407232013-07-28T03:42:36Zalexeymuranov (Alexey Muranov)
<ul></ul><p>=begin<br>
I would suggest</p>
<p>module Enumerable<br>
def to_h<br>
h = {}<br>
each do |e|<br>
h[e.first] = e.last<br>
end<br>
h<br>
end<br>
end<br>
=end</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=414412013-08-31T07:38:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>File</strong> <a href="/attachments/3925">to_h.pdf</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/3925/to_h.pdf">to_h.pdf</a> added</li><li><strong>Status</strong> changed from <i>Feedback</i> to <i>Open</i></li></ul><p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>But I am not sure the following simple implementation works OK, e.g. what if an element is a object, or number, or anything not two-element array.</p>
</blockquote>
<p>Agreed.</p>
<p>I believe we should only treat elements that are array-like and of length 2. More explicitly, either the Enumerable yields one value that responds_to?(:to_ary) and returns a 2-element array, or the Enumerable yields exactly two values. Other cases should be ignored, in the same way that String#to_i ignores invalid characters.</p>
<p>Slide attached.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=414592013-08-31T13:38:32Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Feedback</i></li></ul><p>What I wanted was coner case behavior of #to_h, e.g. what if elements are not 2 elements arrays.<br>
What kind of checks do you want to do?</p>
<p>The simplest implementation in <a class="issue tracker-1 status-5 priority-4 priority-default closed behind-schedule" title="Bug: sprintf() of %f on Windows(MSVCRT) (Closed)" href="https://redmine.ruby-lang.org/issues/6">#6</a> may work, but I'm not sure whether kind of accidental behavior definition is suffice.</p>
<p>Matz.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=414932013-08-31T21:26:02Ztrans (Thomas Sawyer)
<ul></ul><p>=begin<br>
[omit verbose intro] suffice to say we can figure the most fitting definition for (({Enumerable#to_h})) is simply:</p>
<pre><code>module Enumerable
def to_h
a = []
each_with_index.each { |e,i| a << i << e }
Hash[*a]
end
end
[:a,:b].to_h #=> {0=>:a, 1=>:b}
</code></pre>
<p>We can answer why in the nicest of ways too: What is it we are converting to a hash table? It is an ((<em>Enumerable</em>)). So it only stands to reason that the conversion reflect the ((<em>enumeration</em>)). Another nice thing about this definition is there are no corner cases to worry about.</p>
<p>To convert an associative array to a hash, that is a different goal. And as Ruby currently stands, that is best addressed with (({Hash[*assoc.flatten(1)]})). For something better in that regard I would suggest the addition of a new method, maybe (({Hash.from_assoc(assoc)})).<br>
=end</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415052013-09-01T04:05:04Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Status</strong> changed from <i>Feedback</i> to <i>Open</i></li><li><strong>Priority</strong> changed from <i>3</i> to <i>Normal</i></li></ul><p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>What I wanted was coner case behavior of #to_h, e.g. what if elements are not 2 elements arrays.<br>
What kind of checks do you want to do?</p>
<p>The simplest implementation in <a class="issue tracker-1 status-5 priority-4 priority-default closed behind-schedule" title="Bug: sprintf() of %f on Windows(MSVCRT) (Closed)" href="https://redmine.ruby-lang.org/issues/6">#6</a> may work, but I'm not sure whether kind of accidental behavior definition is suffice.</p>
</blockquote>
<p>I think it might be best to ignore anything that is not a key-value pair. So we should use an implementation slightly different from <a class="issue tracker-1 status-5 priority-4 priority-default closed behind-schedule" title="Bug: sprintf() of %f on Windows(MSVCRT) (Closed)" href="https://redmine.ruby-lang.org/issues/6">#6</a>. In Ruby:</p>
<p>module Enumerable<br>
def to_h<br>
h = {}<br>
each_entry do |ary|<br>
next unless ary.respond_to?(:to_ary)<br>
ary = ary.to_ary<br>
raise TypeError unless ary.is_a?(Array)<br>
next unless ary.size == 2<br>
h[e.first] = e.last<br>
end<br>
h<br>
end<br>
end</p>
<p>Note that I am using <code>each_entry</code>, so <code>yield(:key, :value)</code> is treated the same as <code>yield([:key, :value])</code>.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415142013-09-02T10:01:49Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Acceptable. How others think about Marc's rule?</p>
<ul>
<li>elements should respond to #to_ary</li>
<li>return value from #to_ary should be 2 elements array</li>
<li>otherwise the element will be ignored (no TypeError exception)</li>
</ul>
<p>If no one objects, I'd be fine. Marc, do you want to implement it by yourself, or ask somebody to do so?</p>
<p>Matz.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415152013-09-02T11:01:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Assignee</strong> changed from <i>matz (Yukihiro Matsumoto)</i> to <i>marcandre (Marc-Andre Lafortune)</i></li></ul><p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>Marc, do you want to implement it by yourself, or ask somebody to do so?</p>
</blockquote>
<p>Great!<br>
Sure, I can implement it.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415162013-09-02T11:59:30Zphluid61 (Matthew Kerwin)matthew@kerwin.net.au
<ul></ul><p>On Sep 2, 2013 11:02 AM, "matz (Yukihiro Matsumoto)" <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a><br>
wrote:</p>
<blockquote>
<p>Acceptable. How others think about Marc's rule?</p>
<ul>
<li>elements should respond to #to_ary</li>
<li>return value from #to_ary should be 2 elements array</li>
<li>otherwise the element will be ignored (no TypeError exception)</li>
</ul>
</blockquote>
<p>+1, this proposal is as good as any I've seen.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415392013-09-02T18:38:45Zalexeymuranov (Alexey Muranov)
<ul></ul><p>Why #to_ary and not #to_a? Or just expect the elements of the enumerable collection to respond to #first and #last.</p>
<p>If someone implements a class OrderedPair, it is not sure in my opinion that the instances would respond to #to_ary.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415402013-09-02T18:52:49Zalexeymuranov (Alexey Muranov)
<ul></ul><p>I understand that using #to_a or #first and #last directly would give an unexpected result when calling #to_h on a collection of ranges, for example, but one is not supposed to call #to_h on a collection of ranges, or #to_h should be preceded with #select.</p>
<p>The two #next and one #raise look a bit like defensive programming to me, and could cause an unnecessary slowdown. Wouldn't it be better to let the user decide when to precede #to_h with #select?</p>
<p><em>Edited</em></p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415442013-09-03T03:04:35Zalexeymuranov (Alexey Muranov)
<ul></ul><p>Another alternative: since two-element arrays are used here as ordered pairs, maybe the Array class can be extended with #key and #value methods, which would be identical to #first and #last respectively on two-element arrays, and raise errors otherwise. Then #to_h can be implemented as</p>
<pre><code>module Enumerable
def to_h
h = {}
each_entry do |pair|
h[pair.key] = pair.value
end
h
end
end
</code></pre>
<p>It would be then applicable to any collection of objects that respond to #key and #value.</p>
<p>If #key and #value seem to be overused as names, maybe better names can be found (e.g. #key_entry, #value_entry).</p>
<p>So, the idea is to extend Array simultaneously with Enumerable.</p>
<p><em>Edited</em></p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415872013-09-04T02:46:48Ztrans (Thomas Sawyer)
<ul></ul><p>=begin<br>
<a class="user active user-mention" href="https://redmine.ruby-lang.org/users/182">@marcandre (Marc-Andre Lafortune)</a> That implementation is limited by to_ary and it does some weird things.</p>
<pre><code>[ [:a], [:b,1,2], [:c,3] ].to_h #=> {:c=>3}
</code></pre>
<p>I know what you want is to convert an associative array into a hash. That's a good thing to have, I agree! But Enumerable#to_h is not a good method for it. It doesn't "semant".</p>
<p>At most it should be Array#to_h and work like:</p>
<pre><code>[ [:a], [:b,1,2], [:c,3] ].to_h #=> {:a=>nil, :b=>1, :c=>3}
</code></pre>
<p>Or</p>
<pre><code>[ [:a], [:b,1,2], [:c,3] ].to_h #=> {:a=>nil, :b=[1,2], :c=>3}
</code></pre>
<p>Or</p>
<pre><code>[ [:a], [:b,1,2], [:c,3] ].to_h #=> {:a=>[], :b=>[1,2], :c=>[3]}
</code></pre>
<p>Probably it could take an option to select which mode is desired.</p>
<p>On the other hand, I am not so sure it shouldn't have a different name altogether, e.g. <code>Array#assoc_hash</code>.</p>
<p>=end</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415882013-09-04T08:14:29Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p><a class="user active user-mention" href="https://redmine.ruby-lang.org/users/137">@trans (Thomas Sawyer)</a> I am sure</p>
<p>[ [:a], [:b,1,2], [:c,3] ].to_h #=> {:a=>[], :b=>[1,2], :c=>[3]}</p>
<p>is not we want. It destroys common cases for the sake of consistency.</p>
<p>If you want different behavior from proposed one, please show us rational more than vague impression.<br>
For me, using #to_h on non 2 elements array is exceptional, so any behavior is OK if it's well-defined,<br>
and works for common cases.</p>
<p>Matz.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=415962013-09-04T11:15:01Ztrans (Thomas Sawyer)
<ul></ul><p>=begin<br>
<a class="user active user-mention" href="https://redmine.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a></p>
<p>How does it "destroy common case"?</p>
<pre><code>[ [:a,1], [:b,2], [:c,3] ].to_h #=> {:a=>1, :b=>2, :c=>3}
</code></pre>
<p>Would work just fine. That was my first example case.</p>
<p>The next two show what other basic conversions of assoc array to hash there can be. And the "consistent" case you mention certainly can be useful. So my suggestion was to have a parameter, e.g.</p>
<pre><code>class Array
def to_h(type=nil)
h = {}
if type.nil?
each{ |k, v, *| h[k] = v }
elsif type == :array
each{ |k, *v| h[k] = v }
elsif type == :ones
each{ |k, *v| h[k] = v.size > 1 ? v : v[0] }
else
raise ArgumentError, "unknown conversion type for Array#to_h -- `#{type}'"
end
h
end
</code></pre>
<p>That way all are possible.<br>
=end</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416082013-09-04T18:25:08Zalexeymuranov (Alexey Muranov)
<ul></ul><p>By the way, shouldn't the behavior be somewhat consistent with Array#assoc and Array#rassoc? Than would mean, in my opinion,</p>
<pre><code>[[:a, 1], [:a, 2], [:b, 3, 4]].to_h # => {:a=>1, :b=>3} or {:a=>1} or Error, but not {:a=>2}
</code></pre> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416092013-09-04T20:20:20ZEregon (Benoit Daloze)
<ul></ul><p>#to_h should have no parameter, just a single well-defined behavior.<br>
#to_h is for converting for the most simple case(s), if more control is needed, just make your own conversion.</p>
<p>And I think it would be much easier if it was just Hash[] (for arrays), but ignoring instead of raising an exception.<br>
That would be consistency.<br>
Marc-André's rule is Hash[] for an Array with no exceptions and is fine in my opinion.</p>
<p>(One possible case not supported is even length arguments with no nested arrays (Hash[1,2,3,4]), but that is not so well defined as in Hash[*ary] (we miss a level of nesting in Array for the first case). Depending on the first element being an Array or not to detect this case seems a bad idea).</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416122013-09-04T22:04:06Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Alexey, define "consistent" first. It's more difficult than you'd expect.<br>
I don't usually vote for "consistency" except when there's clear benefit.</p>
<p>Matz.</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416172013-09-05T04:17:07Zalexeymuranov (Alexey Muranov)
<ul></ul><p>Matz,</p>
<p>it was just a reminder about <code>#assoc</code> and <code>#rassoc</code>, sorry if it was redundant. IMO, they serve a similar purpose to <code>#to_h</code>: they allow to use an <em>array of two-element arrays</em> as a storage where selection "by key" or "by value" is possible.</p>
<p>I think, if <code>#assoc</code> and <code>#to_h</code> were introduced simultaneously, the following would have given identical results:</p>
<pre><code>[[:a, 1], [:a, 2]].assoc(:a) # => [:a, 1]
[[:a, 1], [:a, 2]].to_h.assoc(:a) # => [:a, 2] with any of the suggested above implementations
</code></pre>
<p>I probably didn't use "consistent" correctly, not in mathematical sense. I meant something closer to "natural": that as many operations or <em>diagrams</em> <em>commute</em> as possible. That is, when appropriate, the result of (({x.foo.bar})) should be the same as that of (({x.bar})), or, if (({#foo})) applies some "essential" transformation to (({x})), but there exists an operation (({#baz})) applicable to (({x.bar})) that is a "counterpart" of (({#foo})), then it would be nice if (({x.foo.bar})) was identical with (({x.bar.baz})), if it makes sense. Here are the corresponding "commuting diagrams" (not exactly, but this gives an idea):</p>
<pre><code>x -- #foo --> x.foo
\ |
#bar #bar
\ |
J V
x.bar == x.foo.bar
x ---------- #foo ----------> x.foo
| |
#bar #bar
| |
V V
x.bar -- #baz --> x.bar.baz == x.foo.bar
</code></pre>
<p>I do not insist, i am just trying to explain what i meant.</p>
<p><em>Update</em>: I think instead of "#to_h is consistent with #assoc", it is more correct to say "#to_h agrees with #assoc".</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416202013-09-05T06:03:49Zalexeymuranov (Alexey Muranov)
<ul></ul><p>Wait! Shouldn't enum.to_h be the same as Hash[enum]?</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416272013-09-05T11:14:07ZAnonymous
<ul></ul><p>I think that there are two basic possibilities for Enumerable#to_h behavior:</p>
<p>Strict:</p>
<p>[[:a, 1], ["b", 2]].to_h #=> { :a => 1, "b" => 2 }</p>
<a name="Anything-else-raises-a-TypeError"></a>
<h1 >Anything else raises a TypeError:<a href="#Anything-else-raises-a-TypeError" class="wiki-anchor">¶</a></h1>
<p>[[:a], ["b", 2]].to_h #=> TypeError<br>
[[:a, 1], ["b", 2, 3]].to_h #=> TypeError</p>
<p>Lax:</p>
<p>[[:a], [:b,1,2], [:c,3]].to_h #=> {:a=>[], :b=>[1,2], :c=>[3]}</p>
<p>"Strict" means, that the method strictly requires the arguments to be size 2 arrays.<br>
"Lax" means, that the arguments are allowed to be arrays of any size >= 1.</p>
<p>I found it useful with plenty of usecases to also define Enumerable#>> as follows:</p>
<p>module Enumerable; def >> other; Hash[ zip other ] end end<br>
[:a, :b, :c] >> [1, 2, 3] #=> {a: 1, b: 2, c: 3}</p>
<p>I also enjoyed to alias #first and #drop(1) with words #car and #cdr:</p>
<p>module Enumerable; def car; first end end<br>
[:a, :b, :c].car #=> :a<br>
module Enumerable; def cdr; drop 1 end end<br>
[:a, :b, :c].cdr #=> [:b, :c]</p>
<p>The "lax" version of the proposed Enumerable#to_h can then be written as:</p>
<p>x = [[:a], [:b, 1, 2], [:c, 3]]<br>
x.map( &:car ) >> x.map( &:cdr ) # <-- This is my opinion what Enumerable#to_h should do.</p>
<p>The last line does what I think that Enumerable#to_h should do. I realize that this<br>
opinion of mine directly contradicts what Matz said earlier. The argument for it would go<br>
somehow like this:</p>
<p>Since there are two basic possibilities for Enumerable#to_h behavior, and the strict one is<br>
already available as Hash[...], Enumerable#to_h should do the other useful thing: The "lax"<br>
version. I noticed similar design pattern between eg. #to_i and Integer(...): Both are useful,<br>
but not the same.</p>
<p>With apologies for arguing,<br>
boris >(°.°)<</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=416422013-09-06T01:18:14Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<ul></ul><p>I vote for raising an exception when trying to convert an invalid array to hash (considering the common case the valid array format).</p> Ruby master - Feature #7292: Enumerable#to_hhttps://redmine.ruby-lang.org/issues/7292?journal_id=425732013-10-24T00:10:51Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>This issue was solved with changeset r43401.<br>
Marc-Andre, thank you for reporting this issue.<br>
Your contribution to Ruby is greatly appreciated.<br>
May Ruby be with you.</p>
<hr>
<ul>
<li>
<p>array.c: Add Array#to_h [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Enumerable#to_h (Closed)" href="https://redmine.ruby-lang.org/issues/7292">#7292</a>]</p>
</li>
<li>
<p>enum.c: Add Enumerable#to_h</p>
</li>
</ul>