Search code examples
c#ironruby

Ruby .each with removal of items in collection


I am currently working with an app that allows for runtime addition and removal of items in a drop down list via a rub script. The Ruby looks like this

SAFE = ;
return control if control.CyclesCount == 0;
control.Items.each{|item| control.Items.Remove(item) if item.Value.index('|').nil?};
return control;

control is custom user control and its Items is a ListItemCollction. I am running via unit tests to get my Ruby code correct and running into some trouble. The ListItemColletion I am passing in looks like this ..

var lic = new ListItemCOllection {
  new ListItem {Text = "Item2", Value = "8"}, 
  new ListItem {Text = "Item1", Value = "1"},
  new ListItem {Text = "Item3", Value = "3|1"},
  new ListItem {Text = "Item4", Value = "4"},
  new ListItem {Text = "Item5", Value = "5|2"},
  new ListItem {Text = "Item6", Value = "6"}
}

Instead of leaving the 2 items with the pipe in them, this code always seems to leave 3 items in the items collection. The 3 depend on the order that I put the items in (while in this order, Item1, Item3, Item5 get left)which leads me to believe that its the remove that is messed up. I have also tried to take a copy of the collection, loop through it, removing from the original so that I was not removing from the collection I was iterating through. I am a relatve noob to Ruby so go easy on me ... but I could use some advice.

Thanks


Solution

  • It is not advisable to change an array while iterating over it. There are some Iterators whose purpose is to change the array.

    a= [1,2,3]
    b= [1,2,3]
    a.delete_if { |x| x == 2 } # => [1,3]
    b.reject! { |x| x == 2 } # => [1,3]
    a # => [1,3]
    b # => [1,3]
    

    Array#delete_if deletes elements of an array. There is only a minor difference to Array#reject

    a= [1,2,3]
    b= [1,2,3]
    a.delete_if { |x| false } # => [1,3]
    b.reject! { |x| false } # => nil
    a # => [1,2,3]
    b # => [1,2,3]
    

    Array#delete_if always returns the remaining array. Array#reject! returns nil instead in case the array remains unchanged.

    Some more modifiieng iterators which, do not change the original array:

    a= [1,2,3]
    a.reject { |x| x == 2 } # => [1,3]
    a # => [1,2,3]
    

    Array#reject returns an array without the rejected elements, but does not modify the original array.

    a= [1,2,3]
    a.select { |x| x != 2 } # => [1,2,3]
    a # => [1,3]
    

    Array#select returns an array of only the selected elements, but does not modify the original array.