rubyprocarray-unique

Why is my filter method not removing some elements that should be removed?


I am trying to create a method called filer_out! that takes in an array and a proc, and returns the same array but with every element that returns true when it is run through the proc, with the caveat being we can't use Array#reject!

I wrote this:

def filter_out!(array, &prc)
    array.each { |el| array.delete(el) if prc.call(el)}
end

arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
p arr_2

but when I run the code, what prints out is:

[7, 5]

even though the answer should be:

[]

Upon review of the solution I see Array#uniq was used first:

def filter_out!(array, &prc)
    array.uniq.each { |el| array.delete(el) if prc.call(el) }
end

arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
p arr_2

and the correct output was displayed:

[]

So I guess what my question is, why do you have to use Array#uniq in order to get the correct solution? thanks for your help!


Solution

  • The problem here is the method delete modify the original array. Here the deal if you put some information out:

    def filter_out!(array, &prc)
      array.each.with_index do |el, i|
        p "Current index #{i}"
        p "Current array #{array}"
        p "Current element #{el}"
        array.delete(el) if prc.call(el)
      end
    end
    
    arr_2 = [1, 7, 3, 5 ]
    filter_out!(arr_2) { |x| x.odd? }
    # Output:
    #"Current index 0"
    # "Current array [1, 7, 3, 5]"
    # "Current element 1"
    # "Current index 1"
    # "Current array [7, 3, 5]"
    # "Current element 3"
    

    Explain:

    By using uniq you get the right result because array.uniq it creates a copy of the original array when the original array is modified, it still iteration as expect.