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!
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:
1
, after it's deleted the array is [7, 3, 5]
1
, it gets the current element with this index in the current array, in this case, is 3
not 7
and delete it, after deleting the array is [3, 5]
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.