9

Say I have an array that looks like:

a = [cat, dog, cat, mouse, rat, dog, cat]

How do I cycle through that, and do something with duplicates - e.g. say delete them?

In other words, if I did a.each do |i|, how do I evaluate a[0], against a[1], a[2], a[3]...and then when I find the one I want, say a[2] in this case has the first duplicate, I then push it to a stack or remove it or something.

I know how to evaluate keys, versus values...but how do I evaluate values against each other within the same array?

Thanks.

10 Answers 10

13

You can create a hash to store number of times any element is repeated. Thus iterating over array just once.

h = Hash.new(0)
['a','b','b','c'].each{ |e| h[e] += 1 }

Should result

 {"a"=>1, "b"=>2, "c"=>1}
Sign up to request clarification or add additional context in comments.

4 Comments

Why not h = Hash.new(0) and h[e] += 1?
Matter of syntax. It's at programmers discretion.
This is actually what I was trying to do....but...I couldn't figure out how to use the nil? and increment methods just like this. Thanks!
Just improving the current answer
6

This works efficiently and is rather simple:

require 'set'

visited = Set.new
array.each do |element|
  if visited.include?(element)
    # duplicated item
  else
    # first appearance
    visited << element
  end
end

Comments

4

Try this:

class Array
    def find_dups
        uniq.map {|v| (self - [v]).size < (self.size - 1) ? v : nil}.compact
    end
end

a = ['cat', 'dog', 'cat', 'mouse', 'rat', 'dog', 'cat']

print a - a.find_dups # Removes duplicates

find_dups will return elements that have duplicates

Comments

3

Try this:

array.inject({}){|h, e| h[e] = h[e].to_i + 1; h}

1 Comment

or array.inject(Hash.new(0)){|h, e| h[e] += 1; h}
2

Use a.uniq! to remove duplicates .

also checkout the ruby-doc.org where you can find more info on ruby's class methods .

2 Comments

compact removes nils from the array. How is it helpful in this situation?
Your solution removes duplicates, it doesn't look for them as OP asked
1

A simple solution is to run a double loop:

a.each_with_index do |a1, idx1|
  a.each_with_index do |a2, idx2|
    next if idx1 >= idx2 # Don't compare element to itself 
                         # and don't repeat comparisons already made

    # do something with a pair of elements (a1, a2)
  end
end

If you just want to eliminate duplicates, there's a method: Array#uniq.

4 Comments

Thought about this, but it seems so messy. There a more elegant, 'ruby-ish' solution?
For eliminating duplicates, there's a method. For comparing all elements to each other, there's a double loop. I personally don't see any mess in it. It's plain simple code that reads well.
Sergio this method is inefficient as you're making unnecessary comparisons that have been made in the past. Your second inner loop should start it's iteration later (i.e. further in the array) on each loop.
@MMM I didn't say it's efficient. I said it's simple :)
1

This will print all the duplicates in an array:

array.inject(Hash.new(0)) { |hash,val| 
  hash[val] += 1; 
  hash 
}.each_pair { |val,count| 
  puts "#{val} -> #{count}" if count > 1 
}

Comments

1

The best way to do it is to compare it with a unique version of itself. If its the same then it has no duplicates, if not then duplicates exist.

unique_array = original_array.uniq

get a unique version of your array

if original_array == unique_array then return true else return false

compare it to your original array.

Simple!

Comments

0

If you just want to get rid of duplicates, the easiest thing to do is take the array and do array&array. Use the & operator.

If you want to know what those repeats are, just compare array to array&array.

Comments

0

If array is sortable, then something like below will return only the duplicates.

array.sort.each_cons(2).select {|p| p[0] == p[1] }.map &:first

Sorts the array, then maps it to consecutive pairs of elements, selects pairs which are same, maps to elements.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.