Reputation: 387
I have a class variable that collects all the instance variables. It also had a method for getting them and deleting them.
module Somemodule
class Widget
@@widgets = []
def initialize
...
@@widgets << self
end
def self.all
@@widgets
end
def delete
@@widgets.delete(self)
end
end
end
In my code, I want to delete widgets sometimes.
module Somemodule
def self.delete_bad_widgets
Widget.all.each do |widget|
if widget.bad
widget.delete
end
end
end
end
The problem is that this doesn't delete all the bad widgets. If I call Widget.all afterwards, I can still see bad widgets. Anyone have any idea what's going on? I'm running Ruby 2.2.1.
Thank you
EDIT: all in all there are about 4500 widgets and the code changes them a couple of times. But I can still run something like the following (in the same delete_bad_widgets method!) and still see bad widgets:
Widget.all.each {|w| pp w if w.bad}
Upvotes: 1
Views: 75
Reputation: 2709
Try using reject!
to remove the bad widgets instead of doing the iteration yourself.
module Somemodule
def self.delete_bad_widgets
Widget.all.reject! {|widget| widget.bad}
end
end
As knut's answer points out, using delete while iterating over an array will cause some elements to be skipped. It's generally not a good idea to insert/delete elements of a collection at the same time you are iterating over that collection.
Also, using reject!
(a.k.a. delete_if
) will perform better since delete
will essentially iterate through the entire array with each call (i.e. reject!
give O(n) performance where -- the way you've used it -- delete
will give O(n^2) worst case performance).
Upvotes: 2
Reputation: 27875
If you delete entries during an each it influences the loop.
Just see this example:
a = [1,2,3,4,5,6,7]
p a
a.each{|x|
p x
a.delete(x) if x == 3
}
p a
The result:
[1, 2, 3, 4, 5, 6, 7]
1
2
3
5
6
7
[1, 2, 4, 5, 6, 7]
The entry 4 is not printed! The each-loop keeps the index, but the sequences changed with your deletion.
I would recommend to implement a class method delete_bad
or a delete_if
.
Upvotes: 3