Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Looping through array, deleting elements

Reply
Thread Tools

Looping through array, deleting elements

 
 
dkmd_nielsen
Guest
Posts: n/a
 
      03-08-2007
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"}

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.

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?

Thanks,
dvn

 
Reply With Quote
 
 
 
 
Tim Hunter
Guest
Posts: n/a
 
      03-08-2007
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?


What about the Array#delete_if method?


--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Farrel Lifson
Guest
Posts: n/a
 
      03-08-2007
On 08/03/07, dkmd_nielsen <(E-Mail Removed)> 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"}
>
> 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.
>
> 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?
>
> Thanks,
> dvn


This sounds like it would be a lot easier with Array#reject or Array#select.

 
Reply With Quote
 
Stefano Crocco
Guest
Posts: n/a
 
      03-08-2007
Alle gioved=EC 8 marzo 2007, dkmd_nielsen ha scritto:
> 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 =3D=3D "FOO"}
>
> 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.
>
> 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?
>
> Thanks,
> dvn


I'm not sure I understand your code (what is that ab in the each block?) At=
=20
any rate, there's method which directly deletes the elements of an array=20
which satisfy a given condition: Array#delete_if:

a=3D[1,2,3,4,5,6]
a.delete_if{|i| i > 3}
=3D> [1,2,3]

This method passes each element of the array to the block, then deletes it =
if=20
the block returns true.

Stefano

 
Reply With Quote
 
Tim Pease
Guest
Posts: n/a
 
      03-08-2007
On 3/8/07, dkmd_nielsen <(E-Mail Removed)> 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

 
Reply With Quote
 
dkmd_nielsen
Guest
Posts: n/a
 
      03-08-2007
On Mar 8, 3:02 pm, "Tim Pease" <(E-Mail Removed)> wrote:
> On 3/8/07, dkmd_nielsen <(E-Mail Removed)> 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


There are a couple of dumb things I have done. First, I had omitted
that block is an object, not of class array. So its each method is
iterating through an array internal to it. Nice little detail to
omit. Duh. Second, there is something called "retry". I was aware
of break, next, and redo, but I was unware of "retry." It worked
great.

I looked at the delete_if. What I could do with that is create a
delete_if method in the class block that implements delete_if. In the
long run, I think that is the best thing to do.

Thanks for everything. One always finds the answer on his/her own
shortly after asking for help.

dvn

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
looping through array elements (noob question) Nate St.germain Ruby 2 06-01-2010 03:49 PM
std::list: remove from front without deleting or looping through whole list Andy C++ 3 06-08-2007 09:02 PM
deleting vector elements while looping thru it kaferro@hotmail.com C++ 16 04-12-2007 12:25 PM
Looping through all Form Elements Mel Javascript 1 08-16-2006 08:12 PM
Looping through form elements Steven K ASP General 3 11-13-2003 02:23 PM



Advertisments