Question

I have solved the problem using normal loops and now using hashes, however I am not confident I used the hashes as well as I could have. Here is my code:

       # 1-100 whats duplicated

def whats_duplicated?(array)
    temp = Hash.new
    output = Hash.new

    # Write the input array numbers to a hash table and count them
    array.each do |element|
        if temp[element] >= 1
            temp[element] += 1
        else
            temp[element] = 1
        end
    end

    # Another hash, of only the numbers who appeared 2 or more times
    temp.each do |hash, count|
        if count > 1
            output[hash] = count
        end
    end
    # Return our sorted and formatted list as a string for screen
    output.sort.inspect
end

### Main
# array_1 is an array 1-100 with duplicate numbers
array_1 = []
for i in 0..99
    array_1[i] = i+1
end

# seed 10 random indexes which will likely be duplicates
for i in 0..9
    array_1[rand(0..99)] = rand(1..100)
end

# print to screen the duplicated numbers & their count
puts whats_duplicated?(array_1)

My question is really what to improve? This is a learning excercise for myself, I am practising some of the typical brain-teasers you may get in an interview and while I can do this easily using loops, I want to learn an efficient use of hashes. I re-did the problem using hashes hoping for efficiency but looking at my code I think it isn't the best it could be. Thanks to anyone who takes an interest in this!

Was it helpful?

Solution 2

def whats_duplicated?(array)
  array.each_with_object(Hash.new(0)) { |val, hsh| hsh[val] += 1 }.select { |k,v| v > 1 }.keys
end

OTHER TIPS

The easiest way to find duplicates in ruby, is to group the elements, and then count how many are in each group:

def whats_duplicated?(array)
  array.group_by { |x| x }.select { |_, xs| xs.length > 1 }.keys
end

whats_duplicated?([1,2,3,3,4,5,3,2])
# => [2, 3]

I would do it this way:

def duplicates(array)
  counts = Hash.new { |h,k| h[k] = 0 }

  array.each do |number|
    counts[number] += 1
  end

  counts.select { |k,v| v > 1 }.keys
end

array = [1,2,3,4,4,5,6,6,7,8,8,9]

puts duplicates(array)
# => [4,6,8]

Some comments about your code: The block if temp[element] == 1 seems not correct. I think that will fail if a number occurs three or more times in the array. You should at least fix it to:

if temp[element]       # check if element exists in hash
  temp[element] += 1   # if it does increment
else
  temp[element] = 1    # otherwise init hash at that position with `1`
end

Furthermore I recommend not to use the for x in foo syntax. Use foo.each do |x| instead. Hint: I like to ask in interviews about the difference between both versions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top