From: Ryan Leavengood Date: 2005-10-18T06:16:44+09:00 Subject: Re: How to get non-unique elements from an array? On 10/17/05, pauldacus@gmail.com wrote: > > And so a test: > > (REGEX) a.sort.join(' ').to_s.scan(/(\d+)\s(\1)+/).flatten.uniq > vs. > (INDEX) a.select{|e| a.index(e) != a.rindex(e)}.uniq > > I ran these on an array with 11,000 elements, 2,000 of which were > duplicates, as follows: > > (1..10000).to_a + (2000..3000).to_a > > The scan (REGEX) script finished in 0.21 seconds > The (INDEX) script ran in 28.77 seconds > > The regex was over 100X faster! Thanks for this. I was wondering if my method of benchmarking might be flawed, and it sort of is in this case. But it makes sense here because the scan just has to make one run through the string, whereas each iteration of the select has multiple calls to an index which might potentially traverse the entire array. As my benchmark shows though, a lot of searches in a smaller array is faster using the index. Also another problem with the string scanning is that it depends on the array elements being numbers (at least in the case above.) I decided to benchmark again using your method and adding some more implementations. Here we go (beware of wrapped lines): require 'benchmark' include Benchmark [[[0,1,2,3,4,5,2,3], 50000],[(1..5000).to_a + (2000..2500).to_a, 1]].each do |a, iterations| bm(12) do |bx| bx.report('simonk') { iterations.times { a.select{|e| a.index(e) != a.rindex(e)}.uniq } } bx.report('samk ') { iterations.times { a.select{|e| a.grep(e).length > 1}.uniq } } bx.report('paul ') { iterations.times { a.sort.join(' ').to_s.scan(/(\d+)\s(\1)+/).flatten.uniq } } bx.report('jeff ') { iterations.times { a.uniq.inject(a.dup) { |b,i| b.delete_at(b.index(i)) ; b } } } bx.report('paolo ') { iterations.times { h = {};u = a.inject([]) {|res, x| h[x] ? res + [x] : h[x] = res}.uniq } } bx.report('jegII ') { iterations.times { seen = Hash.new(0);a.select { |e| (seen[e] += 1) > 1 }.uniq } } bx.report('simons') { iterations.times { uary = a.uniq; a.map.delete_if{|i| x=uary.member?(i); uary.delete(i); x} } } bx.report('robert') { iterations.times { a.inject(Hash.new(0)) {|h,e| h[e]+=1;h}.select {|k,v|v>1}.map {|x,y|x} } } bx.report('david ') { iterations.times { a.uniq.find_all {|x| a.find_all {|y| y == x }.size > 1 } } } bx.report('zach ') { iterations.times { t=[]; a.delete_if{ |e| r=(not t.include? e); t.push(e); r }.uniq } } bx.report('markvh') { iterations.times { t=[]; a.select{ |e| r=t.include?e; t<