The Paper Pilot The Paper Pilot - 1 month ago 9
Ruby Question

Deleting elements of an array based on block with loop

I have an array that I want to remove certain elements from based on a set of rules. I've written the code below:

puts "before: #{people.inspect()}"
puts people.size
people.delete_if do |person|
rules.each do |rule|
if rule.check_source(self) && !rule.check_rule(person)
puts "deleted person #{person.id}"
true
puts "sanity check"
end
end
false
end
puts "after: #{people.inspect()}"


But that code does not work. The array printed before is the same as the array printed after, and "sanity check" is printed, even though I think it shouldn't. I suspect the issue might be because of the loop inside the delete_if block, but I don't know how to fix that.

Here's the console output after an array with 2 people with IDs 2 and 3, where 2 should be deleted and 3 kept:

before: [#<Person id: 2>, #<Person id: 3>]
2
deleted person 2
sanity check
after: [#<Person id: 2>, #<Person id: 3>]

Answer

Your problem is that the block you're handing to delete_if always evaluates to false. Your code structure is like this:

people.delete_if do |person|
  # Stuff that `delete_if` doesn't care about ...
  false
end

The value of the each block doesn't matter since each doesn't care what it returns and delete_if would never see that anyway. The blocks for delete_if and each are independent.

You could replace the whole delete_if block with a simpler any? call:

people.delete_if do |person|
  rules.any? { |rule| rule.check_source(self) && !rule.check_rule(person) }
end

and get the result you're looking for.