https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17097754782011-11-23T05:41:04ZRuby Issue Tracking SystemRuby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223332011-11-23T05:41:04Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<ul></ul><p>+1</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223412011-11-23T07:39:23ZEregon (Benoit Daloze)
<ul></ul><p>You can already do this by using Enumerable#each_with_object or Enumerator#with_object:</p>
<pre><code>[1, 2].each_with_object({}) { |i,h| h[i] = 2*i } # => {1=>2, 2=>4}
</code></pre> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223482011-11-23T08:58:42Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<ul></ul><p>Interesting, I never noticed/used this method before. My only concern is about the naming "each_with_object" when you actually want to inject/accumulate. The code intention is not clear enough when you write each_with_object. Maybe a better alias could be included.</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223552011-11-23T16:17:10ZEdvardM (Edvard Majakari)edvard.majakari@leonidasoy.fi
<ul></ul><p>I also noticed mapAccum* is quite different.</p>
<p>I have to agree with Rodrigo. (each_)with_object seems to really do the thing, but the name is a bit funny one. Then again, that could be just simply aliased in the code for accumulating.</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223562011-11-23T16:51:11Zneleai (Ondrej Bilka)neleai@seznam.cz
<ul></ul><p>Why not just use<br>
Hash[[1,2].map{|a| [a,2*a]}]</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223602011-11-23T19:31:20ZEregon (Benoit Daloze)
<ul></ul><p>Rodrigo Rosenfeld Rosas wrote:</p>
<blockquote>
<p>Interesting, I never noticed/used this method before. My only concern is about the naming "each_with_object" when you actually want to inject/accumulate. The code intention is not clear enough when you write each_with_object. Maybe a better alias could be included.</p>
</blockquote>
<p>I think accumulate implies an accumulator, which you don't have in this case. A Hash does not accumulate values like a growing Integer for example, it rather "register" the key/value entries. The alias of inject, reduce, is actually clear to the intention, you should not use inject with an Array for example (instead of map).</p>
<p>each_with_object is just avoiding the explicit variable definition and returns it:</p>
<p>h = {}<br>
[1, 2].each { |i| h[i] = 2*i }<br>
h</p>
<p>I believe the code I showed is somewhat common in 1.9 and is clear to people knowing about it.</p>
<p>In this particular case, you could probably also use Hash.new:</p>
<p>Hash.new { |h,k| h[k] = k*2 }</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223622011-11-23T20:29:15ZAnonymous
<ul></ul><p>Benoit Daloze wrote :</p>
<blockquote>
<p>h = {}<br>
[1, 2].each { |i| h[i] = 2*i }<br>
h</p>
<p>I believe the code I showed is somewhat common in 1.9 and is clear to people knowing about it.</p>
</blockquote>
<p>I would write<br>
Hash.new.tap do |h|<br>
...<br>
end</p>
<p>Heavier, but the intention is clearer, and without an extra variable (outside of the block).</p>
<p>_md</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223642011-11-23T22:18:08ZEdvardM (Edvard Majakari)edvard.majakari@leonidasoy.fi
<ul></ul><p>Ok.. I'll give real example to show what is typical use case for us:</p>
<p>hash = MyDatabaseObject.get_all.infuse({}) { |h, r| h[normalize_db_key(r.id, r.name)] = r }</p>
<p>after that, code can quickly access any record by id and name saying</p>
<p>obj = hash[normalize_db_key(myid, myname)]</p>
<p>Then again, I'm quite happy with this "each_with_object".</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=223682011-11-24T00:47:21Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>Hi,</p>
<p>Edvard Majakari wrote:</p>
<blockquote>
<p>Ok.. I'll give real example to show what is typical use case for us:</p>
<p>hash = MyDatabaseObject.get_all.infuse({}) { |h, r| h[normalize_db_key(r.id, r.name)] = r }</p>
</blockquote>
<p>As pointed out, you currently have the choice of:</p>
<pre><code>get_all.each_with_object({}) { |r, h| h[normalize_db_key(r.id, r.name)] = r }
Hash[ get_all.map { |r| [normalize_db_key(r.id, r.name), r] } ]
</code></pre>
<p>ActiveSupport also gives you:<br>
get_all.index_by { |r| normalize_db_key(r.id, r.name) }</p>
<p>There is a proposition for Enumerable#associate/categorize in <a href="/issues/4151">[ruby-core:33683]</a> which would give you:<br>
get_all.associate { |r| [normalize_db_key(r.id, r.name), r] }</p>
<p>I also feel your infuse proposal is much too close to inject/each_with_object. Moreover, if you need it mostly to create hashes, it might be best to look into a good way to create hashes (like the proposal for associate/categorize).</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=224172011-11-26T06:53:02Zujihisa (Tatsuhiro Ujihisa)
<ul></ul><blockquote>
<p>new_hash = enum.inject({}) { |h, thing| h[compute_key(thing)] = compute_value(thing); h }</p>
</blockquote>
<blockquote>
<p>while that last h is very easy to add, it is also easy to forget and feels logically not very injectish thing to do. I'd propose this we call 'infuse' in our project:</p>
</blockquote>
<p>It's just because you used <code>[]=</code>. Use <code>merge</code> instead.</p>
<pre><code>new_hash = enum.inject({}) {|h, thing| h.merge compute_key(thing) => compute_value(thing) }
</code></pre>
<p>I don't think we need Enumerable#infuse only for <code>[]=</code>.</p> Ruby master - Feature #5662: inject-accumulate, or Haskell's mapAccum*https://bugs.ruby-lang.org/issues/5662?journal_id=252672012-03-28T00:41:18Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul><p>I think the answer to this original proposal is "use each_with_object".<br>
That's all. Closing.</p>
<p>Please open another ticket for an alias of the method if needed.</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p>