Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

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:

      NABCDEF
      ANBCDEF
      ABNCDEF
      ...
      ABCDEFN
      

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

      NNABCDEF
      NANBCDEF
      ...
      ABCDEFNN
      
      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?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2018-09-22 19:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Eventually, "covfefe" will come to mean:













    Results (190 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!