<?xml version="1.0" encoding="UTF-8"?><rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
> <channel><title>Comments on: Writing A More Ruby-ish Array Intersection Function And Sorting Structs</title> <atom:link href="http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/feed/" rel="self" type="application/rss+xml" /><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/</link> <description>For the betterment of the software craft...</description> <lastBuildDate>Mon, 21 Nov 2011 13:57:06 +0000</lastBuildDate> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.1.2</generator> <item><title>By: Alan Skorkin</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-4379</link> <dc:creator>Alan Skorkin</dc:creator> <pubDate>Sun, 28 Mar 2010 22:55:45 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-4379</guid> <description>Hi Mitch,
You&#039;ve done more with this now than I have :), thanks for taking the time to look at this so closely and then share your findings with everyone.</description> <content:encoded><![CDATA[<p>Hi Mitch,</p><p>You&#8217;ve done more with this now than I have :), thanks for taking the time to look at this so closely and then share your findings with everyone.</p> ]]></content:encoded> </item> <item><title>By: Mitch Kuppinger</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-4375</link> <dc:creator>Mitch Kuppinger</dc:creator> <pubDate>Sun, 28 Mar 2010 15:58:33 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-4375</guid> <description>I&#039;ve played a little further with the Enumerator based list intersect method. There are some optimizations possible.
The if-then-else construct is faster than case.
Taking advantage of the fact that finding the intersection of list pairs is faster on lists of raw integers than on lists of &#039;wrapped&#039; integers, I tried doing the intersect on raw lists that exactly mirror the target wrapped lists. I store the index of the matching integers in the raw list intersect result. I then use that result to pull out the corresponding wrapped integers from wrapped list1. In &#039;wraps w/ prebuilt&#039; raws I used the raws lists that were already created for testing raw list intersection methods. In &#039;wraps build raws&#039; I build the raw lists from scratch within the method.
The latter optimization could, of course, be applied to your methods.
&lt;pre&gt;
ENUMERATOR BASED INTERSECT: CASE vs IF-THEN-ELSE
---------------------------------------------------------
list1 size: 1064  list2 size: 4014
intersect list size: 416
benchmark repeats: 1000
user     system      total        real
case:   17.140000   0.000000  17.140000 ( 17.171875)
if:     14.438000   0.000000  14.438000 ( 14.484375)
ENUMERATOR BASED INTERSECT: RAW LISTS AS PROXIES
---------------------------------------------------------
list1 size: 1064  list2 size: 4014
intersect list size: 416
benchmark repeats: 1000
user     system      total        real
raws only:               15.375000   0.031000  15.406000 ( 15.406250)
wraps only:              49.250000   0.031000  49.281000 ( 49.390625)
wraps w/ prebuilt raws:  17.328000   0.000000  17.328000 ( 17.359375)
wraps build raws:        28.515000   0.016000  28.531000 ( 28.593750)
&lt;/pre&gt;
I cleaned up the code a bit:
&lt;pre&gt;
def isect_raw_indexed(list1,list2)
result = []
e1, e2 = list1.each_with_index, list2.each_with_index
a, b = e1.next, e2.next
while true
if    a[0] &lt; = &gt; b[0] then b = e2.next
else result &lt;&lt; a[1] ;a = e1.next; b = e2.next
end
end
rescue StopIteration; return result
end
def isect_wrapped(list1,list2)
result = []
e1, e2 = list1.each, list2.each
a, b = e1.next, b = e2.next
while true
if    a.value &lt; = &gt; b.value then b = e2.next
else result &lt;&lt; a.value ;a = e1.next; b = e2.next
end
end
rescue StopIteration; return result
end
def isect_wrapped_with_indexed_raws(raws1, raws2, list1)
isects = isect_raw_indexed(raws1, raws2)
isects.inject([]) {&#124;acc,item&#124; acc &lt;&lt; list1[item]}
end
def isect_wrapped_with_indexed_raws2(list1,list2)
r1 = list1.map {&#124;i&#124; i.value}
r2 = list2.map {&#124;i&#124; i.value}
isects = isect_raw_indexed(r1, r2)
isects.inject([]) {&#124;acc,item&#124; acc &lt;&lt; list1[item]}
end
&lt;/pre&gt;</description> <content:encoded><![CDATA[<p>I&#8217;ve played a little further with the Enumerator based list intersect method. There are some optimizations possible.</p><p>The if-then-else construct is faster than case.</p><p>Taking advantage of the fact that finding the intersection of list pairs is faster on lists of raw integers than on lists of &#8216;wrapped&#8217; integers, I tried doing the intersect on raw lists that exactly mirror the target wrapped lists. I store the index of the matching integers in the raw list intersect result. I then use that result to pull out the corresponding wrapped integers from wrapped list1. In &#8216;wraps w/ prebuilt&#8217; raws I used the raws lists that were already created for testing raw list intersection methods. In &#8216;wraps build raws&#8217; I build the raw lists from scratch within the method.</p><p>The latter optimization could, of course, be applied to your methods.</p><pre>
ENUMERATOR BASED INTERSECT: CASE vs IF-THEN-ELSE
---------------------------------------------------------
list1 size: 1064  list2 size: 4014
intersect list size: 416
benchmark repeats: 1000
             user     system      total        real
case:   17.140000   0.000000  17.140000 ( 17.171875)
if:     14.438000   0.000000  14.438000 ( 14.484375)
ENUMERATOR BASED INTERSECT: RAW LISTS AS PROXIES
---------------------------------------------------------
list1 size: 1064  list2 size: 4014
intersect list size: 416
benchmark repeats: 1000
                              user     system      total        real
raws only:               15.375000   0.031000  15.406000 ( 15.406250)
wraps only:              49.250000   0.031000  49.281000 ( 49.390625)
wraps w/ prebuilt raws:  17.328000   0.000000  17.328000 ( 17.359375)
wraps build raws:        28.515000   0.016000  28.531000 ( 28.593750)
</pre><p>I cleaned up the code a bit:</p><pre>
  def isect_raw_indexed(list1,list2)
    result = []
    e1, e2 = list1.each_with_index, list2.each_with_index
    a, b = e1.next, e2.next
    while true
      if    a[0] < = > b[0] then b = e2.next
      else result &lt;&lt; a[1] ;a = e1.next; b = e2.next
      end
    end
    rescue StopIteration; return result
  end
  def isect_wrapped(list1,list2)
    result = []
    e1, e2 = list1.each, list2.each
    a, b = e1.next, b = e2.next
    while true
      if    a.value < = > b.value then b = e2.next
      else result &lt;&lt; a.value ;a = e1.next; b = e2.next
      end
    end
    rescue StopIteration; return result
  end
  def isect_wrapped_with_indexed_raws(raws1, raws2, list1)
    isects = isect_raw_indexed(raws1, raws2)
    isects.inject([]) {|acc,item| acc &lt;&lt; list1[item]}
  end
  def isect_wrapped_with_indexed_raws2(list1,list2)
    r1 = list1.map {|i| i.value}
    r2 = list2.map {|i| i.value}
    isects = isect_raw_indexed(r1, r2)
    isects.inject([]) {|acc,item| acc &lt;&lt; list1[item]}
  end
</pre>]]></content:encoded> </item> <item><title>By: Alan Skorkin</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-4157</link> <dc:creator>Alan Skorkin</dc:creator> <pubDate>Mon, 22 Mar 2010 06:07:22 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-4157</guid> <description>I&#039;ve put back the spaceship operator into the case statement by putting in a space before and after the = sign i.e. &lt; = &gt; :).</description> <content:encoded><![CDATA[<p>I&#8217;ve put back the spaceship operator into the case statement by putting in a space before and after the = sign i.e. < = > :).</p> ]]></content:encoded> </item> <item><title>By: Mitch Kuppinger</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-4155</link> <dc:creator>Mitch Kuppinger</dc:creator> <pubDate>Mon, 22 Mar 2010 05:53:59 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-4155</guid> <description>Corrected code.   When matching values are found both lists have to be advanced.  The termination of the infinite loop was incorrectly done.  The case statement uses a spaceship operator. This does not render well here so I have tried to indicate its presence by adding a surrounding pair of angle brackets.
&lt;pre&gt;
def sorted_list_intersection(list1,list2)
result = []
e1, e2 = list1.each,  list2.each
a, b = e1.next,  e2.next
while true
begin
case a &lt; = &gt; b
when -1 then a = e1.next
when +1 then b = e2.next
else result &lt;&lt; a; a = e1.next; b = e2.next
end
rescue StopIteration;  return result
end
end
end
&lt;/pre&gt;</description> <content:encoded><![CDATA[<p>Corrected code.   When matching values are found both lists have to be advanced.  The termination of the infinite loop was incorrectly done.  The case statement uses a spaceship operator. This does not render well here so I have tried to indicate its presence by adding a surrounding pair of angle brackets.</p><pre>
def sorted_list_intersection(list1,list2)
  	result = []
  	e1, e2 = list1.each,  list2.each
  	a, b = e1.next,  e2.next
  	while true
  	  begin
  		case a < = > b
  		  when -1 then a = e1.next
  		  when +1 then b = e2.next
  		  else result &lt;&lt; a; a = e1.next; b = e2.next
  		end
  	  rescue StopIteration;  return result
  	  end
  	end
  end
</pre>]]></content:encoded> </item> <item><title>By: Alan Skorkin</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-3887</link> <dc:creator>Alan Skorkin</dc:creator> <pubDate>Sun, 14 Mar 2010 22:57:50 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-3887</guid> <description>Intersection is implemented in C for arrays, so it is much faster than a pure ruby solution like mine. I&#039;ve actually posted some quick time comparisons in one of my previous posts. Browsing the C source, it does look like the algorithm used is similar to the one I describe, although difficult to say for sure without spending way longer trying to grok the C code.</description> <content:encoded><![CDATA[<p>Intersection is implemented in C for arrays, so it is much faster than a pure ruby solution like mine. I&#8217;ve actually posted some quick time comparisons in one of my previous posts. Browsing the C source, it does look like the algorithm used is similar to the one I describe, although difficult to say for sure without spending way longer trying to grok the C code.</p> ]]></content:encoded> </item> <item><title>By: Mitch Kuppinger</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-3886</link> <dc:creator>Mitch Kuppinger</dc:creator> <pubDate>Sun, 14 Mar 2010 16:28:13 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-3886</guid> <description>Sets in 1.9 support intersection, union and difference methods. Sets in 1.9 are not, I think, ordered. I have no idea how intersection, for example, is implemented so cannot guess how its performance would compare with the intersection method in your post. Perhaps one of your readers has some information.</description> <content:encoded><![CDATA[<p>Sets in 1.9 support intersection, union and difference methods. Sets in 1.9 are not, I think, ordered. I have no idea how intersection, for example, is implemented so cannot guess how its performance would compare with the intersection method in your post. Perhaps one of your readers has some information.</p> ]]></content:encoded> </item> <item><title>By: Mitch Kuppinger</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-3885</link> <dc:creator>Mitch Kuppinger</dc:creator> <pubDate>Sun, 14 Mar 2010 15:19:46 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-3885</guid> <description>Oops! special characters were removed. The last line of my last post should read:
The method also depends on an appropriate definition of the &#039;space-ship operator&#039;.  &quot;&quot;</description> <content:encoded><![CDATA[<p>Oops! special characters were removed. The last line of my last post should read:</p><p>The method also depends on an appropriate definition of the &#8216;space-ship operator&#8217;.  &#8220;&#8221;</p> ]]></content:encoded> </item> <item><title>By: Mitch Kuppinger</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-3884</link> <dc:creator>Mitch Kuppinger</dc:creator> <pubDate>Sun, 14 Mar 2010 15:15:34 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-3884</guid> <description>I should point out that this is ruby 1.9 syntax and usage. I think there has been a backport of this into 1.8.7. the ruby facets library may have some of the same functionality. I have not played with either of those.  David Black&#039;s &#039;The Well -Grounded Rubyist&#039; has a nice section on Enumerators. It was my intro tho them. The 1.9 API docs are also helpful.
The begin..end pair are not needed in a method definition. The while is just to setup an infinite loop that is exited when an error (StopIteration ) is raised. So I can clean the example up a bit:
&lt;pre&gt;
def sorted_set_intersection(seta,setb)
result = []
ea = seta.each
eb = setb.each
a = ea.first
b = eb.first
loop do
case a &lt; = &gt; b
when -1: a = ea.next
when +1: b = eb.next
else result &lt;&lt; a
end
end
rescue StopIteration
result
end
&lt;/pre&gt;
Enumerators raise the StopIteration error when they move beyond the end of the enumerable by single stepping through.
The method also depends on an appropriate definition of &lt; = &gt;</description> <content:encoded><![CDATA[<p>I should point out that this is ruby 1.9 syntax and usage. I think there has been a backport of this into 1.8.7. the ruby facets library may have some of the same functionality. I have not played with either of those.  David Black&#8217;s &#8216;The Well -Grounded Rubyist&#8217; has a nice section on Enumerators. It was my intro tho them. The 1.9 API docs are also helpful.</p><p>The begin..end pair are not needed in a method definition. The while is just to setup an infinite loop that is exited when an error (StopIteration ) is raised. So I can clean the example up a bit:</p><pre>
  def sorted_set_intersection(seta,setb)
  	result = []
  	ea = seta.each
  	eb = setb.each
  	a = ea.first
  	b = eb.first
  	loop do
  	  case a < = > b
  		when -1: a = ea.next
  		when +1: b = eb.next
  		else result &lt;&lt; a
  	  end
  	end
  rescue StopIteration
  	result
  end
</pre><p>Enumerators raise the StopIteration error when they move beyond the end of the enumerable by single stepping through.</p><p>The method also depends on an appropriate definition of < = ></p> ]]></content:encoded> </item> <item><title>By: Alan Skorkin</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-3883</link> <dc:creator>Alan Skorkin</dc:creator> <pubDate>Sun, 14 Mar 2010 13:24:38 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-3883</guid> <description>Ah I see what you&#039;re getting at, pretty cool. This definitely has possibilities, I&#039;ll have to play with this further</description> <content:encoded><![CDATA[<p>Ah I see what you&#8217;re getting at, pretty cool. This definitely has possibilities, I&#8217;ll have to play with this further</p> ]]></content:encoded> </item> <item><title>By: Mitch Kuppinger</title><link>http://www.skorks.com/2010/03/writing-a-more-ruby-ish-array-intersection-function-and-sorting-structs/comment-page-1/#comment-3881</link> <dc:creator>Mitch Kuppinger</dc:creator> <pubDate>Sun, 14 Mar 2010 03:50:11 +0000</pubDate> <guid
isPermaLink="false">http://www.skorks.com/?p=1402#comment-3881</guid> <description>Use enumerators:
def intersection(seta,setb)
ea = seta.each; a = ea.first
eb = setb.each; b= eb.first
result = []
begin
while true
case a  b
when -1: a = ea.next
when +1: b = eb.next
else result &lt;&lt; a
end
end
rescue
result
end
end
this of course assumes seta and setb are ordered</description> <content:encoded><![CDATA[<p>Use enumerators:</p><p>def intersection(seta,setb)<br
/> ea = seta.each; a = ea.first<br
/> eb = setb.each; b= eb.first<br
/> result = []<br
/> begin<br
/> while true<br
/> case a  b<br
/> when -1: a = ea.next<br
/> when +1: b = eb.next<br
/> else result &lt;&lt; a<br
/> end<br
/> end<br
/> rescue<br
/> result<br
/> end<br
/> end</p><p>this of course assumes seta and setb are ordered</p> ]]></content:encoded> </item> </channel> </rss>
