Modifying Array inside While statement

A

Andy

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.
 
G

Gunnar Hjalmarsson

Andy said:
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?

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?
 
J

Jürgen Exner

Andy said:
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.

That's what you asked perl to do.
Say if I
have 10 elements in my_array, then the while loop is executed 10
times.

Yep, that's as expected.
There are about six times the 'shift' gets executed but it
does not affect the number of iterations of the while loop.

It shouldn't affect the number of iterations because you remove each element
only _after_ you started the iteration for that particular element already.
What can be the workaround for this?

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
 
P

Paul Lalli

A. Sinan Unur said:
Could you please post real Perl?

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
 
P

Paul Lalli

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

while (<@my_array>) {

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
 
R

robic0

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:
If valid, are you thinking that @my_array should be an array of file
handles?
Bizzarro world..
 
J

John W. Krahn

Andy said:
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?

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


John
 
A

A. Sinan Unur

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.

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
 
C

ced

Andy said:
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;
}
}

....


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

hth,
 
C

ced

John said:
How would that help?

Too many twists and turns... I meant:

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


--
Charles DeRykus





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

ced

Anno said:
Better written as

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

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
C

ced

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.
 
C

ced

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.
 
A

Anno Siegel

[...]

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.

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
 
C

ced

Anno said:
(e-mail address removed) .....


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;

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/;
}
 
C

ced

...
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;

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/;
}

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.
 
J

John W. Krahn

Anno said:
(e-mail address removed) ....

...
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;

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/;
}

Or:

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



John
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top