Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

Iterating over an array variable times

by gingaloon (Acolyte)
on Aug 05, 2008 at 14:45 UTC ( #702380=perlquestion: print w/replies, xml ) Need Help??
gingaloon has asked for the wisdom of the Perl Monks concerning the following question:

Hi everybody, I have an array that I wish to iterate over and each time insert an index. This I can do. My problem is that sometimes I wish to iterate twice, inserting in two positions. This I can also do (see below). However, I cannot come up with a nice way of potentially doing both in a clean piece of code. I have one for the former and one for latter.

Can anyone point me in the right direction? Thanks

my @arr=qw/A B C D E F/; print join (",",@arr),"\n"; for (my $i=0;$i<=$#arr+1;$i++) { for (my $j=$i+1;$j<=$#arr+2;$j++) { my @tmp=@arr; splice @tmp,$i,0,'N'; splice @tmp,$j,0,'N'; print join (",",@tmp),"\n"; } }

Replies are listed 'Best First'.
Re: Iterating over an array variable times
by ikegami (Pope) on Aug 05, 2008 at 16:15 UTC
    To extend your algorithm to make the number of loops arbitrary, use Algorithm::Loops's NestedLoops.
    use strict; use warnings; use Algorithm::Loops qw( NestedLoops ); my @arr = qw( A B C D E F ); my $N = 2; my $i = NestedLoops([ [ 0 .. @arr ], ( sub { [ $_ .. @arr ] } ) x ($N-1) ]); while (my (@positions) = $i->()) { my @tmp = @arr; splice(@tmp, $_, 0, 'N') for reverse @positions; print(join(',', @tmp), "\n"); }

    Or without inserting elements in the middle of an array (which should help with long arrays):

    while (my (@positions) = $i->()) { my @tmp; my $cur = 0; for my $pos (@positions) { push @tmp, @arr[$cur..$pos-1]; $cur = $pos; push @tmp, 'N'; } push @tmp, @arr[$cur..$#arr]; print(join(',', @tmp), "\n"); }

    Or a version that uses no extra memory.

    while (my (@positions) = $i->()) { my $sep = ''; my $cur = 0; for my $pos (@positions) { print($sep); $sep = ', '; print($arr[$cur++], $sep) while $cur < $pos; print('N'); } print($sep, $arr[$cur++]) while $cur < @arr; print("\n"); }
      Thanks Jethro and Ikegami.
      These do what I need.  I shall now read through what each bit of code is doing.
      thanks again
Re: Iterating over an array variable times
by jethro (Monsignor) on Aug 05, 2008 at 16:13 UTC
    One possible way would be to do a routine that calculates the next state from the previous one no matter how many 'N's are in the array. That way you just put the number of 'N's at the beginning of the array and call the routine repeatedly until all 'N's are at the end of the array

    use warnings; use strict; my @arr=qw/A B C D E F/; my $anzahl=2; unshift @arr, ('N') x $anzahl; print join (",",@arr),"\n"; while (@arr= step (@arr)) { print join (",",@arr),"\n"; } sub step { # returns empty list if all marks are already at the end my @arr= @_; my $marksatend=0; my $i= @arr; #count marks at the end while ($i) { if ($arr[--$i] eq 'N') { $marksatend++; } else { last; } } #find a mark to advance my $mark=-1; while ($i) { if ($arr[--$i] eq 'N') { $mark=$i; last; } } #advance if ($mark<0) { return (); } else { my $tmp= $arr[$mark]; $arr[$mark]= $arr[$mark+1]; $arr[$mark+1]= $tmp; if ($marksatend>0) { splice @arr,-$marksatend; splice @arr,$mark+2,0, ('N')x$marksatend; } return @arr; } }
Re: Iterating over an array variable times
by metaperl (Curate) on Aug 05, 2008 at 15:15 UTC
    I figured someone would've replied to you by now, but since they haven't let me break the ice.
    1. What is you overall functional goal? Don't speak in code, just tell us what your business requirement is.
    2. What determines whether you want to iterate once or twice?
    3. Please show your code for iterating once. I only see the code for iterating twice.
Re: Iterating over an array variable times
by metaperl (Curate) on Aug 05, 2008 at 15:21 UTC
    I ran the code above and got this:
    A,B,C,D,E,F N,N,A,B,C,D,E,F N,A,N,B,C,D,E,F N,A,B,N,C,D,E,F N,A,B,C,N,D,E,F N,A,B,C,D,N,E,F N,A,B,C,D,E,N,F N,A,B,C,D,E,F,N A,N,N,B,C,D,E,F A,N,B,N,C,D,E,F A,N,B,C,N,D,E,F A,N,B,C,D,N,E,F A,N,B,C,D,E,N,F A,N,B,C,D,E,F,N A,B,N,N,C,D,E,F A,B,N,C,N,D,E,F A,B,N,C,D,N,E,F A,B,N,C,D,E,N,F A,B,N,C,D,E,F,N A,B,C,N,N,D,E,F A,B,C,N,D,N,E,F A,B,C,N,D,E,N,F A,B,C,N,D,E,F,N A,B,C,D,N,N,E,F A,B,C,D,N,E,N,F A,B,C,D,N,E,F,N A,B,C,D,E,N,N,F A,B,C,D,E,N,F,N A,B,C,D,E,F,N,N
    Is this what you wanted? What does that represent? How is that useful to you? Needless to say, you always want use strict; use warnings; in your code.
      The output is what I wanted and I apologise for not pasting in the opening lines of a longer script.

      I have a string of letters, e.g. 'ABCDEF'. I want to insert the letter 'N' into each position so I can end up with:


      At other times I'll need to insert a second N into the string, which is the output given in a previous post:

      Whether I need one or two iterations is controled by an input that we can call $num.

      I can do this insertion for one instance and also for two instances, but I've written them as two sets of code. I'm wondering if there's a way to do it in once block of code.

      many thanks

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://702380]
Approved by toolic
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (11)
As of 2018-11-21 14:17 GMT
Find Nodes?
    Voting Booth?
    My code is most likely broken because:

    Results (239 votes). Check out past polls.