3

This is not a problem, but more of a question if there are other ways to do this:

I have an array:

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

I want this output: [2,5]

My code looks like this:

arr.select { |e| arr.count(e) == 1}

Are there some alternatives to this?

Stefan
  • 109,145
  • 14
  • 143
  • 218
Eugen
  • 155
  • 2
  • 9

3 Answers3

10

Try this

arr.group_by { |e| e }.select { |k, v| v.size.eql? 1 }.keys
 => [2, 5] 
Alok Anand
  • 3,346
  • 1
  • 20
  • 17
4

Your code will scan the array once per element which is acceptable for small arrays, but it should not be necessary. By looking at this blog post it is easy to come up with

arr = [1,2,3,4,4,5,1,4,3]
counts=Hash.new(0)

arr.each do |el|
  counts[el]+=1
end

counts.select do |key, count|
  count == 1
end.keys

which yields the same result but only traverses your array once (at the expense of two additional hashes though (which you can reduce to one by using select! if you do not need the counts :-).

Patru
  • 4,481
  • 2
  • 32
  • 42
  • Thanks @bjhaid, did not think of that, of course you would go with `select!` in the one liner ;-) – Patru Mar 13 '14 at 13:08
  • 1
    `arr.each_with_object(Hash.new(0)) { |x,h| h[x] += 1 }.select { |k,v| v == 1 }.keys` is the one-liner :) – bjhaid Mar 13 '14 at 13:14
4

One needs to have a look at the whole array first to decide the uniqueness

def one(a)
  o = { }
  a.each do |x|
    v = o[x]
    if v == nil
      o[x] = true
    else
      if v
        o[x] = false
      end
    end
  end
  return o
end

and then use this to pick the unique elements

def unique(a)
  o = one(a)
  b = [ ]
  o.each do |k, v|
    if v
      b.push(k)
    end
  end
  return b
end

Test code

a = [ 1, 2, 3, 4, 4, 5, 1, 4, 3 ]
b = unique(a)
puts "unique: #{a} -> #{b}"

Output

unique: [1, 2, 3, 4, 4, 5, 1, 4, 3] -> [2, 5]

Dedicated to Edsger W. Dijkstra

A modern, competent programmer should not be puzzle-minded, he should not revel in tricks, he should be humble and avoid clever solutions like the plague

(from EWD303)

mvw
  • 5,075
  • 1
  • 28
  • 34
  • I updated it after realizing that there is no need to count over 2, thus keeping the counts small, even if we would have high repetitions. Would you be so nice to update that benchmark? – mvw Mar 13 '14 at 15:04