0

I initialize an array that has a duplicate element, and then I try to find that very element through a nested each loop.

array=(1..100).to_a
array.insert(5, 100)

array.each do |x|
  m = x
  array.delete(x)
  array.each do |y|
    if m == y
      puts m
    end
  end
end

Anyone have an idea why this does not work?

sawa
  • 165,429
  • 45
  • 277
  • 381
gskang
  • 27
  • 1
  • 9
  • If you don't have to specifically solve this by using nested loops, check out this thread: http://stackoverflow.com/questions/8921999/ruby-how-to-find-and-return-a-duplicate-value-in-array – bork Mar 26 '16 at 22:07

3 Answers3

1

The problem is caused by modifying the array (with delete) while you iterate over that array.

In the first iteration the iterator "points" to the first element in the array. Since you delete that first element, the second element becomes the first. In the next iteration the iterator points to the second element in the array - the one that was the third in the first iteration. You skip the element that was the second in the first iteration and move to the front.

As you see you would not check each element instead you only check every second element.

It might be a bit more efficient to sort the array first and then only check each consecutive elements if they are equal:

array.sort.each_cons(2) { |x, y| puts(x) if x == y }
spickermann
  • 100,941
  • 9
  • 101
  • 131
0

Array#delete deletes all of the identical objects in the array, not just the first one.

ar = [1,2,1]
ar.delete(1)
p ar  #=> [2]
steenslag
  • 79,051
  • 16
  • 138
  • 171
0

Here's an efficient way to find the first duplicate element.

require 'set'
s = Set.new
[1,3,2,5,3,4,7].find { |e| !s.add?(e) }
  #=> 3

The method Set#add? attempts to add its argument to the set. If successful, it returns the argument; else (the set already contains its argument) it returns nil. As sets are hashes under the covers, lookups are very quick.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100