Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting items from an array requires multiple passes to remove them all

Tags:

regex

ruby

I have an array of ~1200 ruby objects and I want to loop over them and delete the ones with names that contain words or parts of words.

So I tried this:

list.each do |item|
  if item.name =~ /cat|dog|rat/i
    puts item.name
    list.delete(item)
  end
end

It works, except that it seems to miss some items with names that should match. If I run it again it finds a few more, and if I run it another time it finds a few more. It finds less each time, but I have to run it 3 times in order to delete everything.

Why in the world is this happening?

like image 584
Seth Archer Brown Avatar asked Apr 11 '11 03:04

Seth Archer Brown


Video Answer


2 Answers

That's you modifying underlying collection while iterating over it.
Basically, if collection changes in some way during iteration (becomes empty, gets prepended with a new element, etc), iterator doesn't have a lot of ways to handle it.

Try reject instead.

list.reject! {|item| item.name =~ /cat|dog|rat/i }
like image 173
Nikita Rybak Avatar answered Sep 23 '22 15:09

Nikita Rybak


There is another way to do the same as reject! with delete:

list.delete_if { |item| item =~  /cat|dog|rat/i }
like image 36
Fran Martinez Avatar answered Sep 21 '22 15:09

Fran Martinez