user2536488
user2536488

Reputation: 1

Return the elements present exactly once in an array

I am a beginner in Ruby. Can anyone help me to write code for this, please?

Given an Array, return the elements that are present exactly once in the array.

For example, it should pass the following test cases:

Upvotes: 0

Views: 354

Answers (3)

Arup Rakshit
Arup Rakshit

Reputation: 118289

a = [1,2,2,3,3,4,5]
p a.select{|i| a.count(i) == 1}
# >> [1, 4, 5]


a = [1,2,2,3,4,4]
p a.select{|i| a.count(i) == 1}
# >> [1, 3]

Benchmarks

require 'benchmark'

a = [1,2,2,3,3,4,5]

n = 1000000
Benchmark.bm(15) do |x|
  x.report('priti') { n.times { a.select{|i| a.count(i) == 1} } }
  x.report('Jason') { n.times { a.group_by { |x| x }.reject { |k,v| v.count > 1 }.keys } }
  x.report('rogerdpack2') { n.times {
    bad = {}
    good = {}
    a.each{|v|
      if bad.key? v
        # do nothing
      else
        if good.key? v
          bad[v] = true
          good.delete(v)
        else
          good[v] = true;
        end
      end
    }
    good.keys            
  }
 }
end

with this result

 priti             3.152000   0.000000   3.152000 (  3.247000)
 Jason             4.633000   0.000000   4.633000 (  4.845000)
 rogerdpack2       3.853000   0.000000   3.853000 (  3.886000)

and with a larger array:

require 'benchmark'

a = [1,2,2,3,3,4,5]*5 + [33,34]

n = 1000000
Benchmark.bm(15) do |x|
  x.report('priti') { n.times { a.select{|i| a.count(i) == 1} } }
  x.report('Jason') { n.times { a.group_by { |x| x }.reject { |k,v| v.count > 1 }.keys } }
  x.report('rogerdpack2') { n.times {
    bad = {}
    good = {}
    a.each{|v|
      if bad.key? v
        # do nothing
      else
        if good.key? v
          bad[v] = true
          good.delete(v)
        else
          good[v] = true;
        end
      end
    }
    good.keys            
  }
 }
 x.report('priti2') { n.times { a.uniq.select{|i| a.count(i) == 1} }}
end

you get result:

                  user     system      total        real
 priti            60.435000   0.000000  60.435000 ( 60.769151)
 Jason            10.827000   0.016000  10.843000 ( 10.978195)
 rogerdpack2       9.141000   0.000000   9.141000 (  9.213843)
 priti2           15.897000   0.000000  15.897000 ( 16.007201)

Upvotes: 4

rogerdpack
rogerdpack

Reputation: 66851

Here's another option:

a = [1,2,2,3,3,4,5]
b = {}
a.each{|v|
  b[v] ||= 0
  b[v] += 1
}
b.select{|k, v| v == 1}.keys

and here's a potentially faster one (though more complex) that is hard coded to look for items "just listed once":

a = [1,2,2,3,3,4,5]
bad = {}
good = {}
a.each{|v|
  if bad.key? v
    # do nothing
  else
    if good.key? v
      bad[v] = true
      good.delete(v)
    else
      good[v] = true;
    end
  end
}
good.keys

Upvotes: 0

Jason
Jason

Reputation: 3806

Put the items in an array. a = [1,2,2,3,4,4] Then run a few filters to get the items you want.

a.group_by { |x| x }.reject { |k,v| v.count > 1 }.keys

#=> [1,3]

Updated With Stefan's keys suggestion.

Upvotes: 5

Related Questions