https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112019-07-02T16:14:41ZRuby Issue Tracking SystemRuby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=790482019-07-02T16:14:41Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>Hmm. I don't doubt that this may possibly be useful, but the method name is<br>
a bit ... weird. My first association with this name, oddly enough, is to<br>
associate duck typing with it, and then to "pluck the duck" (yes, strange<br>
association but I could not help it ...).</p>
<p>I do not have a better alternative suggestion for a name, though. It<br>
reminds me a little bit of a more flexible variant of .dig(), though.</p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=796792019-07-16T07:13:33Zinopinatus (Joshua GOODALL)
<ul></ul><p>I think that's pretty limited. #pluck is a fairly crude method, fine for Rails but hardly befitting the Ruby standard library. I'd much rather use a higher-order function and get somewhere much more interesting.</p>
<p>By instead implementing <code>Array#to_proc</code> (which doesn't currently exist) as something that applies to_proc to its own elements, before invoking them with passed-in arguments:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Array</span>
<span class="k">def</span> <span class="nf">to_proc</span>
<span class="no">Proc</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">tail</span><span class="o">|</span>
<span class="n">collect</span><span class="p">(</span><span class="o">&</span><span class="ss">:to_proc</span><span class="p">).</span><span class="nf">collect</span> <span class="k">do</span> <span class="o">|</span><span class="n">ep</span><span class="o">|</span>
<span class="n">ep_head</span> <span class="o">=</span> <span class="n">ep</span><span class="p">[</span><span class="n">head</span><span class="p">]</span>
<span class="n">tail</span><span class="p">.</span><span class="nf">empty?</span> <span class="p">?</span> <span class="n">ep_head</span> <span class="p">:</span> <span class="p">[</span><span class="n">ep_head</span><span class="p">]</span> <span class="o">+</span> <span class="n">tail</span><span class="p">.</span><span class="nf">collect</span><span class="p">(</span><span class="o">&</span><span class="n">ep</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>we can now do some nice things, including a pluck equivalent (and more besides) but using only existing syntax:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># data</span>
<span class="n">people</span> <span class="o">=</span> <span class="p">[{</span><span class="ss">name: </span><span class="s2">"Park"</span><span class="p">,</span> <span class="ss">age: </span><span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="ss">name: </span><span class="s2">"Lee"</span><span class="p">,</span> <span class="ss">age: </span><span class="mi">31</span><span class="p">}]</span>
<span class="n">keys</span> <span class="o">=</span> <span class="n">people</span><span class="p">.</span><span class="nf">flat_map</span><span class="p">(</span><span class="o">&</span><span class="ss">:keys</span><span class="p">).</span><span class="nf">uniq</span>
<span class="c1"># single item extraction</span>
<span class="ss">:name</span><span class="p">.</span><span class="nf">then</span> <span class="o">&</span><span class="n">people</span> <span class="c1">#=> ["Park", "Lee"] and equivalent to</span>
<span class="n">people</span><span class="p">.</span><span class="nf">to_proc</span><span class="p">[</span><span class="ss">:name</span><span class="p">]</span> <span class="c1">#=> ["Park", "Lee"]</span>
<span class="c1"># multiple item extraction</span>
<span class="n">keys</span><span class="p">.</span><span class="nf">then</span> <span class="o">&</span><span class="n">people</span> <span class="c1">#=> [["Park", 42], ["Lee", 31]] and equivalent to</span>
<span class="n">people</span><span class="p">.</span><span class="nf">to_proc</span><span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:age</span><span class="p">]</span> <span class="c1">#=> [["Park", 42], ["Lee", 31]]</span>
<span class="c1"># multiple method invocation</span>
<span class="ss">:name</span><span class="p">.</span><span class="nf">then</span><span class="p">(</span><span class="o">&</span><span class="n">people</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="p">[</span><span class="ss">:upcase</span><span class="p">,</span> <span class="ss">:length</span><span class="p">])</span> <span class="c1">#=> [["PARK", 4], ["LEE", 3]]</span>
<span class="c1"># use with struct-like objects, and bonus inline lambda:</span>
<span class="n">people</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="no">OpenStruct</span><span class="o">.</span><span class="ss">:new</span><span class="p">).</span><span class="nf">map</span> <span class="o">&</span><span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:age</span><span class="p">,</span> <span class="o">-></span><span class="p">{</span> <span class="no">Digest</span><span class="o">::</span><span class="no">SHA2</span><span class="p">.</span><span class="nf">hexdigest</span> <span class="err">@</span><span class="mi">1</span><span class="p">.</span><span class="nf">name</span> <span class="p">}]</span>
</code></pre>
<p>Could work as <code>Enumerable#to_proc</code> instead.</p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=796802019-07-16T07:47:04Zosyo (manga osyo)
<ul></ul><blockquote>
<p>we can now do some very nice things just with existing syntax:</p>
</blockquote>
<p>The sample code is invalid.<br>
Is this?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Array</span>
<span class="k">def</span> <span class="nf">to_proc</span>
<span class="no">Proc</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">tail</span><span class="o">|</span>
<span class="n">collect</span><span class="p">(</span><span class="o">&</span><span class="ss">:to_proc</span><span class="p">).</span><span class="nf">collect</span> <span class="k">do</span> <span class="o">|</span><span class="n">ep</span><span class="o">|</span>
<span class="n">ep_head</span> <span class="o">=</span> <span class="n">ep</span><span class="p">[</span><span class="n">head</span><span class="p">]</span>
<span class="n">tail</span><span class="p">.</span><span class="nf">empty?</span> <span class="p">?</span> <span class="n">ep_head</span> <span class="p">:</span> <span class="p">[</span><span class="n">ep_head</span><span class="p">]</span> <span class="o">+</span> <span class="n">tail</span><span class="p">.</span><span class="nf">collect</span><span class="p">(</span><span class="o">&</span><span class="n">ep</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># data</span>
<span class="n">people</span> <span class="o">=</span> <span class="p">[{</span><span class="ss">name: </span><span class="s2">"Park"</span><span class="p">,</span> <span class="ss">age: </span><span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="ss">name: </span><span class="s2">"Lee"</span><span class="p">,</span> <span class="ss">age: </span><span class="mi">31</span><span class="p">}]</span>
<span class="c1"># single item extraction</span>
<span class="nb">p</span> <span class="ss">:name</span><span class="p">.</span><span class="nf">then</span> <span class="o">&</span><span class="n">people</span> <span class="c1">#=> ["Park", "Lee"]</span>
<span class="nb">p</span> <span class="n">people</span><span class="p">.</span><span class="nf">to_proc</span><span class="p">[</span><span class="ss">:name</span><span class="p">]</span> <span class="c1">#=> ["Park", "Lee"]</span>
<span class="c1"># multiple item extraction</span>
<span class="nb">p</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:age</span><span class="p">].</span><span class="nf">then</span> <span class="o">&</span><span class="n">people</span> <span class="c1">#=> [["Park", 42], ["Lee", 31]]</span>
<span class="nb">p</span> <span class="n">people</span><span class="p">.</span><span class="nf">to_proc</span><span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:age</span><span class="p">]</span> <span class="c1">#=> [["Park", 42], ["Lee", 31]]</span>
<span class="c1"># multiple invocation</span>
<span class="n">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Park"</span><span class="p">,</span> <span class="s2">"Lee"</span><span class="p">]</span>
<span class="nb">p</span> <span class="n">names</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="p">[</span><span class="ss">:upcase</span><span class="p">,</span> <span class="ss">:length</span><span class="p">])</span> <span class="c1">#=> [["PARK", 4], ["LEE", 3]]</span>
</code></pre>
<p><a href="https://wandbox.org/permlink/4oVOzULhwKsu4gB5" class="external">https://wandbox.org/permlink/4oVOzULhwKsu4gB5</a></p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=796862019-07-17T02:54:09Zinopinatus (Joshua GOODALL)
<ul></ul><p>My apologies, yes, there was a cut-and-paste error on show for a few minutes, and you were quick enough to see it. It's now the code I intended to paste.</p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=813442019-09-02T06:19:44Zknu (Akinori MUSHA)knu@ruby-lang.org
<ul></ul><p>ActiveSupport has <a href="https://api.rubyonrails.org/classes/Enumerable.html#method-i-pluck" class="external">Enumerable#pluck</a>, so I don't think we want to diverge from that by adding a method with the same name in Array.</p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=813462019-09-02T06:28:50Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>I am not positive for <code>Array#pluck</code>. ActiveSupport may add the method.</p>
<p>Matz.</p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=889452020-12-06T17:18:38Zconnorshea (Connor Shea)
<ul></ul><p>I was going to suggest the same thing because I think it's a very useful shorthand! Here's an example I run into a lot when manipulating data in my Ruby scripts.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Lets say I have an array of hashes representing video games (this is pretty</span>
<span class="c1"># common because I write a decent amount of scripts manipulating data in Ruby).</span>
<span class="n">games</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span>
<span class="ss">title: </span><span class="s2">"Half-Life 2"</span><span class="p">,</span>
<span class="ss">steam_id: </span><span class="mi">1</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="ss">title: </span><span class="s2">"Portal"</span><span class="p">,</span>
<span class="ss">steam_id: </span><span class="mi">2</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="ss">title: </span><span class="s2">"Portal 2"</span><span class="p">,</span>
<span class="ss">steam_id: </span><span class="mi">3</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="c1"># If I want to get the Steam IDs for all those, for example to match this</span>
<span class="c1"># dataset with another dataset to find overlaps, I need to use a `map` like</span>
<span class="c1"># this:</span>
<span class="n">games</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">game</span><span class="o">|</span> <span class="n">game</span><span class="p">[</span><span class="ss">:steam_id</span><span class="p">]</span> <span class="p">}</span> <span class="c1">#=> [1, 2, 3]</span>
<span class="c1"># That code above doesn't really spark joy, it's pretty lengthy for something</span>
<span class="c1"># that should be very simple.</span>
<span class="c1"># What I _want_ to do is something like this, but since these are just hash</span>
<span class="c1"># keys, I can't:</span>
<span class="n">games</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:steam_id</span><span class="p">)</span> <span class="c1">#=> undefined method `steam_id'</span>
<span class="c1"># The best solution would be a `#pluck` method:</span>
<span class="n">games</span><span class="p">.</span><span class="nf">pluck</span><span class="p">(</span><span class="ss">:steam_id</span><span class="p">)</span> <span class="c1">#=> [1, 2, 3]</span>
<span class="c1"># This sparks joy!</span>
</code></pre>
<p>Please consider adding a <code>#pluck</code> method on <code>Enumerable</code> 🙇♂️</p>
<p>Ideally it'd accept more than one argument to get multiple values at once, but that's not really a deal-breaker for me if we don't include it.</p>
<p>Maybe it could be called <code>#pick</code>, <code>#each_dig</code>, <code>#map_keys</code>, or something else?</p> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=889482020-12-06T18:01:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul><p>Matz has already stated that it's a no, so I will close this.</p>
<p>I'll add that the issue should not be about a shorthand to <code>map</code> and calling <code>[]</code> or <code>dig</code>, but how to write concisely <code>{|game| game[:steam_id]}</code>. As <a class="user active user-mention" href="https://redmine.ruby-lang.org/users/13618">@inopinatus (Joshua GOODALL)</a> said, maybe a variant of <code>to_proc</code> could make this more concise, but that is what <code>_1</code> is for. This is short and concise:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">games</span><span class="p">.</span><span class="nf">map</span><span class="p">{</span> <span class="n">_1</span><span class="p">[</span><span class="ss">:steam_id</span><span class="p">]</span> <span class="p">}</span>
</code></pre> Ruby master - Feature #15975: Add Array#pluckhttps://redmine.ruby-lang.org/issues/15975?journal_id=889522020-12-06T23:53:28Zphluid61 (Matthew Kerwin)matthew@kerwin.net.au
<ul></ul><p>Apologies for posting to a closed ticket, but here's a thought in case it helps someone propose something else in future: partial application in <code>#to_proc</code>, e.g. <code>games.map(&(:[], :steam_id))</code></p>
<p>I hate the syntax I just invented, but the idea of partial application to the right (i.e. applying args to a proc before applying the receiver) is interesting.</p>