Modifying Array inside While statement

Discussion in 'Perl Misc' started by Andy, Dec 27, 2005.

  1. Andy

    Andy Guest

    I have a perl script that takes an array and processes the arguments
    inside it.

    while (<@my_array>) {
    print "$_";
    if (/new/i) {
    @new_array = shift @my_array;
    }
    }

    Now I expect as while loop progresses, the array @my_array shrinks but
    the while loop get executed for all the indices in @my_array. Say if I
    have 10 elements in my_array, then the while loop is executed 10 times.
    There are about six times the 'shift' gets executed but it does not
    affect the number of iterations of the while loop.
    What can be the workaround for this?

    thanks,
    Anand.
     
    Andy, Dec 27, 2005
    #1
    1. Advertisements

  2. Workaround? Guess it depends on what you are trying to do.

    What does the array look like initially?

    How do you want it to be afterwards?
     
    Gunnar Hjalmarsson, Dec 27, 2005
    #2
    1. Advertisements

  3. That's what you asked perl to do.
    Yep, that's as expected.
    It shouldn't affect the number of iterations because you remove each element
    only _after_ you started the iteration for that particular element already.
    Well, there is no workaround. Your script is behaving exactly as expected.
    Unfortunately you are not telling us what you indented to do, so we cannot
    tell you how to achive what you meant to achive.

    jue
     
    Jürgen Exner, Dec 27, 2005
    #3
  4. Could you please post real Perl?

    Sinan
     
    A. Sinan Unur, Dec 27, 2005
    #4
  5. Andy

    Paul Lalli Guest

    Could you please *try* what is written before assuming the OP is lying
    to us?

    With -MO=Deparse, the above comes out to:

    use File::Glob ();
    while (defined($_ = glob(join($", @my_array)))) {


    Certainly one of the most bizarre "features" I've seen yet, but
    syntactically valid.

    Paul Lalli
     
    Paul Lalli, Dec 27, 2005
    #5
  6. Andy

    Paul Lalli Guest

    Where did you learn this syntax? What do you believe this is doing?
    I'm relatively sure it's not what you're expecting. If you run this
    code with -MO=Deparse, you will see that this comes out to:

    use File::Glob ();
    while (defined($_ = glob(join($", @my_array)))) {

    Therefore, that glob is operating on the string composed of the
    elements of @my_array, separated by a space. That string is created
    and evaluated once, and then glob returns each matching result once per
    evaluation of the while() conditional. Changes to @my_array do not
    effect it.

    I'm *guessing* what you wanted to do was:
    while (@my_array) {

    which will cause the block to be evaluated so long as @my_array
    contains at least one item.

    Or perhaps you simply want to iterate through each element of the
    array, assigning $_ to each successive element?

    foreach (@my_array) {

    is what you want in that case.

    Paul Lalli
     
    Paul Lalli, Dec 27, 2005
    #6
  7. Andy

    robic0 Guest

    If valid, are you thinking that @my_array should be an array of file
    handles?
    Bizzarro world..
     
    robic0, Dec 27, 2005
    #7
  8. my @new_array = grep /new/i, @my_array;


    John
     
    John W. Krahn, Dec 27, 2005
    #8
  9. It'll take me a while to wrap my mind around that. In the mean time,
    apologies to the OP and everyone else for jumping the gun, and thank you
    for pointing out my error.

    Sinan
     
    A. Sinan Unur, Dec 27, 2005
    #9
  10. Andy

    ced Guest


    @my_array = map { /new/i ? () : $_ } @my_array;

    hth,
     
    ced, Dec 28, 2005
    #10
  11. How would that help?


    John
     
    John W. Krahn, Dec 28, 2005
    #11
  12. Andy

    ced Guest

    Too many twists and turns... I meant:

    @new_array = map { /new/i ? $_ : () } @my_array;


    --
    Charles DeRykus





    @my_array = map /new/i ? () : $_ } @my_array;
     
    ced, Dec 28, 2005
    #12
  13. Andy

    Anno Siegel Guest

    Better written as

    @new_array = grep /new/i, @my_array;

    Anno
     
    Anno Siegel, Dec 28, 2005
    #13
  14. Andy

    ced Guest

     
    ced, Dec 28, 2005
    #14
  15. Andy

    ced Guest

    Sorry for the earlier empty response. Yup, shorter and clearer.
    Likely
    more efficient too but that's often a lesser issue.

    Neither may satisfy the original intent though... I notice the OP's
    code
    did a shift() which suggests he may have wanted to remove matched
    items @my_array as well as capture them in @new_array.
     
    ced, Dec 28, 2005
    #15
  16. Andy

    ced Guest

    Sorry for the earlier empty response. Yup, shorter and clearer.
    Likely
    more efficient too but that's often a lesser issue.

    Neither may satisfy the original intent though... I notice the OP's
    code
    did a shift() which suggests he may have wanted to remove matched
    items @my_array as well as capture them in @new_array.
     
    ced, Dec 28, 2005
    #16
  17. Andy

    Anno Siegel Guest

    Hard to say what the OP intended with a while loop over a glob. Could
    be something like a two-way grep (untested):

    my ( @one, @two);
    for ( @my_array ) {
    if ( /pattern/ ) {
    push @one, $_;
    } else {
    push @two, $_;
    }
    }

    or even, compactified,

    push @{ /pattern/ ? \ @one : \ @two }, $_ for @my_array;

    Anno
     
    Anno Siegel, Dec 29, 2005
    #17
  18. Andy

    ced Guest

    Or, maybe, if the OP really did intend to remove matched items
    in-place:

    for ( reverse 0..$#my_array) {
    unshift @new_array, splice @my_array, $_, 1 if $my_array[$_] =~
    /new/;
    }
     
    ced, Dec 29, 2005
    #18
  19. Andy

    ced Guest

    Of course, that's a bit of a function monstrosity. It'd be clearer
    and
    faster to just re-assign after your 2-way grep:
    :

    @my_array = @one;

    .... unless, I suppose, you had some neurotic distaste for
    intermediates.
     
    ced, Dec 29, 2005
    #19
  20. Or:

    push @{ /new/i ? \@new_array : \@my_array }, $_ for splice @my_array;



    John
     
    John W. Krahn, Dec 29, 2005
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.