https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112015-12-15T04:33:13ZRuby Issue Tracking SystemRuby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555432015-12-15T04:33:13Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Is there any real world example?</p>
<p>Matz.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555462015-12-15T05:15:19ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul></ul><p>Matz, alas, I cannot offer one. You see, Ruby--coding generally--is just a hobby for me. I spend a fair bit of time answering Ruby questions on SO and would have reached for this method on many occasions had it been available. Perhaps readers with development experience (everybody but me?) could reflect on whether this method would have been useful in projects they've worked on.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555482015-12-15T06:56:32ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/55548/diff?detail_id=39694">diff</a>)</li></ul> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555492015-12-15T07:02:51ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/55549/diff?detail_id=39695">diff</a>)</li></ul> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555502015-12-15T08:01:06Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<ul></ul><p>Cary Swoveland wrote:</p>
<blockquote>
<p>I spend a fair bit of time answering Ruby questions on SO and would have reached for this method on many occasions had it been available.</p>
</blockquote>
<p>Then why don't you just provide pointers to those SO (StackOverflow?) questions, with explanations on how Array#difference would make things easier?</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555512015-12-15T08:47:56ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul></ul><p>Martin Dürst wrote:</p>
<blockquote>
<p>Then why don't you just provide pointers to those SO (StackOverflow?) questions, with explanations on how Array#difference would make things easier?</p>
</blockquote>
<p>Martin, see my <a href="http://stackoverflow.com/questions/24987054/how-to-select-unique-elements" class="external">SO answer here</a>, which contains links to a number of questions where I did use the method in my answer.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555522015-12-15T12:27:01Zdanielpclark (Daniel P. Clark)6ftdan@gmail.com
<ul></ul><p>I like how your <strong>Array#difference</strong> method works well with duplicate entries. I've only come across times where the difference of id references between two lists needed to be determined. In my case it's</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="c1"># example</span>
<span class="n">b</span> <span class="o">-</span> <span class="n">a</span>
<span class="c1"># => [1, 3, 1, 3]</span>
<span class="n">b</span> <span class="o">-</span> <span class="n">a</span> <span class="o">|</span> <span class="n">a</span> <span class="o">-</span> <span class="n">b</span>
<span class="c1"># => [1, 3, 6, 8]</span>
</code></pre>
<p>Like the example you first gave with added <code>| b - a</code> for getting two way evaluation on uniqueness. If I wanted to get the same thing with Array#difference it looks the same as my example above.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="c1"># example</span>
<span class="n">b</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="c1"># => [1, 3, 1, 3]</span>
<span class="n">a</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">|</span> <span class="n">b</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="c1"># => [1, 3, 6, 8]</span>
</code></pre>
<p>So as to not cause confusion these are not the same as I will demonstrate with Cary Swoveland's input.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">b</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="c1"># => [4] </span>
<span class="n">b</span> <span class="o">-</span> <span class="n">a</span>
<span class="c1"># => []</span>
<span class="n">a</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="c1"># => [1, 3, 2, 2] </span>
<span class="n">a</span> <span class="o">-</span> <span class="n">b</span>
<span class="c1"># => [1]</span>
</code></pre>
<p>As far as a real world use case for <strong>Array#difference</strong>: Service (A) exports all data to CSV files with a background worker. Service (B) exports to a database with a background worker. Sometimes a background worker crashes. Now to figure out what's missing we compare the difference between to two datasets. <em>One flaw in my example is there is no determination in the position the new data needs to be entered to match the other. In this case we would need to use something like Enumerator#with_index</em></p>
<p>@Cary Swoveland; If I could make one recommendation on the implementation. I think it would be best to have it implemented as an <strong>Enumerator</strong> so it can be performed with lazy evaluation. That way when the difference is being compared we can perform operations along the way and "potentially" save system resources.</p>
<p>Here's the Enumerator that will give the same results as your code.</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">difference</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="n">cpy</span> <span class="o">=</span> <span class="n">other</span><span class="p">.</span><span class="nf">dup</span>
<span class="no">Enumerator</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">y</span><span class="o">|</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">e</span><span class="o">|</span>
<span class="n">ndx</span> <span class="o">=</span> <span class="n">cpy</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ndx</span>
<span class="n">cpy</span><span class="p">.</span><span class="nf">delete_at</span><span class="p">(</span><span class="n">ndx</span><span class="p">)</span>
<span class="k">elsif</span> <span class="o">!</span><span class="n">cpy</span><span class="p">.</span><span class="nf">empty?</span>
<span class="n">y</span> <span class="o"><<</span> <span class="n">e</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I must admit that I am biased toward Enumerators over simple Array results. If this is never used on anything complex then it won't need to be an Enumerator.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555622015-12-15T17:37:12ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul></ul><p>Daniel, thank you for your interesting observations. I too am fond of enumerators (<code>[true, false].cycle</code> being a fav), and I can see the advantages here. In my second example, for example, one could write <code>w1.chars.difference(w2.chars).none? #=> true</code>, avoiding the need for the construction of a temporary array. On the other hand, if the method were often used in conjunction with other <code>Array</code> methods, tacking on <code>to_a</code> may become tiresome. The last line of my first example would become <code>u - a.difference(u).to_a</code>, my third example would be <code>a.difference(b).to_a.concat(b.difference(a).to_a)</code> and your example would be <code>a.difference(b).to_a | b.difference(a).to_a</code>.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=555662015-12-15T17:52:21Zdanielpclark (Daniel P. Clark)6ftdan@gmail.com
<ul></ul><p>I see your point. Looking into how <code>Enumerator::Lazy</code> works it looks like a good solution for having both.</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">difference</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="nb">dup</span><span class="p">.</span><span class="nf">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">cpy</span><span class="o">|</span>
<span class="n">other</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">e</span><span class="o">|</span>
<span class="n">ndx</span> <span class="o">=</span> <span class="n">cpy</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="n">cpy</span><span class="p">.</span><span class="nf">delete_at</span><span class="p">(</span><span class="n">ndx</span><span class="p">)</span> <span class="k">if</span> <span class="n">ndx</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Enumerator::Lazy</span>
<span class="k">def</span> <span class="nf">difference</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="n">cpy</span> <span class="o">=</span> <span class="n">other</span><span class="p">.</span><span class="nf">dup</span>
<span class="no">Lazy</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="nb">self</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">y</span><span class="p">,</span> <span class="n">e</span><span class="o">|</span>
<span class="n">ndx</span> <span class="o">=</span> <span class="n">cpy</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ndx</span>
<span class="n">cpy</span><span class="p">.</span><span class="nf">delete_at</span><span class="p">(</span><span class="n">ndx</span><span class="p">)</span>
<span class="k">elsif</span> <span class="o">!</span><span class="n">cpy</span><span class="p">.</span><span class="nf">empty?</span>
<span class="n">y</span> <span class="o"><<</span> <span class="n">e</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">a</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="c1"># => [1, 3, 2, 2]</span>
<span class="n">a</span><span class="p">.</span><span class="nf">lazy</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="nf">next</span>
<span class="c1"># => 1</span>
<span class="n">a</span><span class="p">.</span><span class="nf">lazy</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="nf">force</span>
<span class="c1"># => [1, 3, 2, 2]</span>
</code></pre>
<p>This works well.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=556432015-12-18T03:48:46Zrp.beltran (Ryan Beltran)rp.beltran@yahoo.com
<ul></ul><p>Yukihiro Matsumoto wrote:</p>
<blockquote>
<p>Is there any real world example?</p>
<p>Matz.</p>
</blockquote>
<p>I think I have a pretty good example. I'm implementing a function in Ruby that finds triples in an array for use in a pokerbot (recognizes if a hand is a triple). I already defined a function to check for doubles (which is relatively trivial to implement by comparing the original array to array.uniq), but triples are a little bit harder. There are several ways I could implement checking for triples, but a concise and efficient option would be to simply call:</p>
<p><code>getDoubles(array.difference(array.uniq))</code></p>
<p>This works because if an array has a triple, then the difference between it and a set of it's unique values will have a double of the same value as the triple. This is much nicer than any methods I have come up with iteratively.</p>
<p>With array. difference can also define a more elegant alternative to what I was using for doubles as:</p>
<p><code>array.difference(array.uniq).uniq</code></p>
<p>If I want to build the lists of doubles, triples, and four of a kind, I can define them even more elegantly as:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">doubles</span> <span class="o">=</span> <span class="n">array</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">array</span><span class="p">.</span><span class="nf">uniq</span><span class="p">)</span>
<span class="n">triples</span> <span class="o">=</span> <span class="n">doubles</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">doubles</span><span class="p">.</span><span class="nf">uniq</span><span class="p">)</span>
<span class="n">fours</span> <span class="o">=</span> <span class="n">triples</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">triples</span><span class="p">.</span><span class="nf">uniq</span><span class="p">)</span>
</code></pre>
<p>And this pattern continues on as shown.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=556562015-12-18T10:17:38Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<ul></ul><p>Ryan Beltran wrote:</p>
<blockquote>
<p>I think I have a pretty good example. I'm implementing a function in Ruby that finds triples in an array for use in a pokerbot (recognizes if a hand is a triple). I already defined a function to check for doubles (which is relatively trivial to implement by comparing the original array to array.uniq), but triples are a little bit harder. There are several ways I could implement checking for triples, but a concise and efficient option would be to simply call:</p>
<p><code>getDoubles(array.difference(array.uniq))</code></p>
</blockquote>
<blockquote>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">doubles</span> <span class="o">=</span> <span class="n">array</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">array</span><span class="p">.</span><span class="nf">uniq</span><span class="p">)</span>
<span class="n">triples</span> <span class="o">=</span> <span class="n">doubles</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">doubles</span><span class="p">)</span>
<span class="n">fours</span> <span class="o">=</span> <span class="n">triples</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">triples</span><span class="p">)</span>
</code></pre>
</blockquote>
<p>An even more straightforward way is to use group_by:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">n_tuples</span> <span class="o">=</span> <span class="n">array</span><span class="p">.</span><span class="nf">group_by</span> <span class="p">{</span><span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="n">e</span><span class="p">}.</span><span class="nf">values</span><span class="p">.</span><span class="nf">group_by</span><span class="p">(</span><span class="o">&</span><span class="ss">:length</span><span class="p">)</span>
<span class="n">doubles</span> <span class="o">=</span> <span class="n">n_tuples</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="n">triples</span> <span class="o">=</span> <span class="n">n_tuples</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
<span class="n">fours</span> <span class="o">=</span> <span class="n">n_tuples</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
<span class="c1"># and so on</span>
<span class="o">~~~</span> <span class="n">ruby</span>
<span class="no">We</span> <span class="n">need</span> <span class="n">group_by</span> <span class="n">two</span> <span class="n">times</span> <span class="n">because</span> <span class="n">the</span> <span class="n">first</span> <span class="n">one</span> <span class="n">groups</span> <span class="n">items</span> <span class="n">with</span> <span class="n">the</span> <span class="n">same</span> <span class="n">value</span><span class="p">,</span> <span class="ow">and</span> <span class="n">the</span> <span class="n">second</span> <span class="n">organizes</span> <span class="n">these</span> <span class="n">by</span> <span class="n">numbers</span><span class="o">.</span> <span class="no">As</span> <span class="n">an</span> <span class="n">example</span><span class="p">,</span> <span class="k">if</span> <span class="n">we</span> <span class="n">start</span> <span class="n">with</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">8</span><span class="p">]</span> <span class="k">then</span> <span class="n">after</span> <span class="n">the</span> <span class="n">first</span> <span class="n">group_by</span><span class="p">,</span> <span class="n">we</span> <span class="n">have</span>
<span class="p">{</span><span class="mi">1</span><span class="o">=></span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">2</span><span class="o">=></span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="mi">3</span><span class="o">=></span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="mi">4</span><span class="o">=></span><span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span> <span class="mi">5</span><span class="o">=></span><span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span> <span class="mi">7</span><span class="o">=></span><span class="p">[</span><span class="mi">7</span><span class="p">],</span> <span class="mi">8</span><span class="o">=></span><span class="p">[</span><span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">]}</span><span class="o">.</span>
<span class="no">Of</span> <span class="n">this</span><span class="p">,</span> <span class="n">we</span> <span class="n">only</span> <span class="n">need</span> <span class="n">the</span> <span class="ss">values: </span><span class="p">[[</span><span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span> <span class="p">[</span><span class="mi">7</span><span class="p">],</span> <span class="p">[</span><span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">]]</span><span class="o">.</span>
<span class="no">Then</span> <span class="n">we</span> <span class="n">group</span> <span class="n">by</span> <span class="n">length</span> <span class="ow">and</span> <span class="ss">get:
</span><span class="p">{</span><span class="mi">1</span><span class="o">=></span><span class="p">[[</span><span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">7</span><span class="p">]],</span> <span class="mi">2</span><span class="o">=></span><span class="p">[[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">]],</span> <span class="mi">3</span><span class="o">=></span><span class="p">[[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">]],</span> <span class="mi">4</span><span class="o">=></span><span class="p">[[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">]]}</span>
<span class="no">To</span> <span class="n">get</span> <span class="n">an</span> <span class="n">unique</span> <span class="n">value</span> <span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="nf">e</span><span class="o">.</span> <span class="mi">3</span> <span class="n">instead</span> <span class="n">of</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">]),</span> <span class="n">just</span> <span class="n">use</span> <span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:first</span><span class="p">)</span><span class="o">.</span>
</code></pre> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=556792015-12-19T19:22:46ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/55679/diff?detail_id=39759">diff</a>)</li></ul> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=602112016-08-19T22:43:52ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/60211/diff?detail_id=42276">diff</a>)</li></ul><p>Implemented the method in a clearer and more efficient manner.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=605192016-09-15T16:43:20ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/60519/diff?detail_id=42444">diff</a>)</li></ul> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=665902017-09-10T23:56:16ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/66590/diff?detail_id=46100">diff</a>)</li></ul> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=742422018-09-29T14:14:24Zfebeling (Florian Ebeling)florian.ebeling@gmail.com
<ul></ul><p>I could use this method for fixing this bug [1] in ActiveRecord.</p>
<p>To me it looks like a valuable addition.</p>
<p>It's about replacing collection associations which can be partially persisted, with persisted records being handled differently as an optimization.</p>
<p>1 <a href="https://github.com/rails/rails/issues/33942" class="external">https://github.com/rails/rails/issues/33942</a></p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=742462018-09-30T12:16:46Zfebeling (Florian Ebeling)florian.ebeling@gmail.com
<ul></ul><p>And analogously an method 'Array#intersection' would be valuable. Implementation could share most code.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=743192018-10-05T20:04:12Zfebeling (Florian Ebeling)florian.ebeling@gmail.com
<ul></ul><p>Now that <code>Array#difference</code> has in <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Add union and difference to Array (Closed)" href="https://redmine.ruby-lang.org/issues/14097">#14097</a> become an operator with set semantics, this proposal should probably be closed.</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=758382018-12-21T23:18:44ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/75838/diff?detail_id=50719">diff</a>)</li></ul> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=866252020-07-20T19:58:00ZTylerRick (Tyler Rick)tyler@tylerrick.com
<ul></ul><p>I would really like to see this included in Ruby.</p>
<p>Is there anything we can do to move this forward?</p>
<p>Do we just need to find a good name for it, now that <code>Array#difference</code> has been added with set semantics the same as <code>Array#-</code>?</p> Ruby master - Feature #11815: Proposal for method `Array#difference`https://redmine.ruby-lang.org/issues/11815?journal_id=866262020-07-20T23:34:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>Note that <code>Enumerable#tally</code> make many of these tasks based on the number of appearances reasonably easy to do. In the examples of the original poster:</p>
<p>Determine if two arrays of the same size contain the same elements</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
<span class="n">a</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="nf">empty?</span>
<span class="c1">#=> true</span>
<span class="c1"># Use tally:</span>
<span class="n">a</span><span class="p">.</span><span class="nf">tally</span> <span class="o">==</span> <span class="n">b</span><span class="p">.</span><span class="nf">tally</span>
<span class="c1"># => true</span>
<span class="c1"># assuming they can't be sorted, otherwise using sort works too:</span>
<span class="n">a</span><span class="p">.</span><span class="nf">sort</span> <span class="o">==</span> <span class="n">b</span><span class="p">.</span><span class="nf">sort</span>
</code></pre>
<p>Identify an array's unique elements</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">u</span> <span class="o">=</span> <span class="n">a</span><span class="p">.</span><span class="nf">uniq</span> <span class="c1">#=> [1, 2, 3, 4]</span>
<span class="n">u</span> <span class="o">-</span> <span class="n">a</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">u</span><span class="p">)</span> <span class="c1">#=> [1, 2]</span>
<span class="c1"># Use tally:</span>
<span class="n">a</span><span class="p">.</span><span class="nf">tally</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span><span class="o">|</span><span class="n">k</span><span class="p">,</span> <span class="n">nb</span><span class="o">|</span> <span class="n">nb</span> <span class="o">==</span> <span class="mi">1</span><span class="p">}.</span><span class="nf">keys</span> <span class="c1"># => [1, 2]</span>
<span class="c1"># Makes it easy to select elements on a diffent criteria, e.g. == 2 for exactly duplicated, etc.</span>
</code></pre>
<p>Identify a maximal number of 1-1 matches between the elements of two arrays and return an array of all elements from both arrays that were not matched</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">7</span><span class="p">]</span>
<span class="n">a</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="nf">concat</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="nf">difference</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>
<span class="c1">#=> [1, 1, 4, 2, 9, 3, 7] </span>
<span class="n">a</span><span class="p">.</span><span class="nf">tally</span><span class="p">.</span><span class="nf">merge</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="nf">tally</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">_</span><span class="p">,</span> <span class="n">nb_a</span><span class="p">,</span> <span class="n">nb_b</span><span class="o">|</span> <span class="n">nb_a</span> <span class="o">-</span> <span class="n">nb_b</span> <span class="p">}.</span><span class="nf">flat_map</span> <span class="p">{</span> <span class="o">|</span><span class="n">obj</span><span class="p">,</span> <span class="n">n</span><span class="o">|</span> <span class="p">[</span><span class="n">obj</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span><span class="p">.</span><span class="nf">abs</span> <span class="p">}</span>
</code></pre>