From: Tim Pease Date: 2007-03-09T06:02:53+09:00 Subject: Re: Looping through array, deleting elements On 3/8/07, dkmd_nielsen wrote: > My idea of looping through an array, interrogating elements that are > of class instruction, and deleting the element does not appear to work > as I thought. I think I know why. What is the best solution? > > block.each {|i| ab.delete(i) if i.parm == "FOO"} > Not a good idea! You are modifying the array as you iterate over it -- this will cause some unexpected behavior: ary = [1,2,3,4] ary.each {|x| ary.delete(x) if x > 2} p ary #=> [1, 2, 4] oops! > where block is a series of elements of class instruction(i). Class > instruction has two attributes, parm and arg. If the instruction parm > is FOO, then delete the instruction object from the array and keep > looping. Half of what should be deleted actually get's deleted. I > think the reason is: the loop is looking at element x foo, element x > foo get's deleted, the array is shifted left, array pointer has not > changed but is now referencing element y foo, loop advances the array > pointer, and now array pointer is pointing at element z foo. > You are correct. What happens is that we delete the number 3 from the array and this compacts the array -- 4 shifts into the position where 3 just was. Now the "each" method moves the index to the next position thereby skipping the number 4. > If what I think is correct, what is the best solution? Do I set the > current element to nil, then compact the array after the loop? Do I > delete the instruction and then do a redo? Or is there a better > solution than those? > Use the delete_if method on the array. ary.delete_if {|x| x > 2} p ary #=> [1,2] Blessings, TwP