Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re: Ignore a range of numbers in a List

by shmem (Chancellor)
on Jun 25, 2017 at 08:11 UTC ( [id://1193496]=note: print w/replies, xml ) Need Help??


in reply to Ignore a range of numbers ina List

I am trying to splice the array on the copy and not original array But looks like the loop ends before it can read the next 6 in the list

It's not the loop ending prematurely, it is wrong indices.

This happens because splice shrinks the array @copy, and after that, the original and copy arrays aren't aligned any more. You need yet another variable which holds the amount of elements spliced off, and decrease $sixindex by that amount at the next splice operation, otherwise the offset is outside the @copy array.

Adding some debug print statements shows the problem:

#!/usr/bin/perl use warnings; use strict; use Data::Dump; ######## my $aref = [1, 6, 2, 2, 7, 1, 6, 99, 99, 7]; my $flag = 0; my $i = 1; my $sixindex = 0; my @copy = @$aref; if (scalar(@$aref) >= 2) { foreach my $x (0..$#{$aref}) { print "pass $x\n"; dd $aref; dd \@copy; if (defined($aref->[$x])) { if ($aref->[$x] == 6) { $flag = 1; $sixindex = $x; next; } if ($flag) { unless ($aref->[$x] == 7) { $i++; next; } elsif ($aref->[$x] == 7 ) { print "splice $sixindex, ",($i+1),"\n"; splice(@copy, $sixindex, $i + 1); $flag = 0; $i = 1; $sixindex = 0; next; } } } } } dd \@copy; __END__ pass 0 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] pass 1 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] pass 2 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] pass 3 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] pass 4 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] splice 1, 4 pass 5 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 1, 6, 99, 99, 7] pass 6 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 1, 6, 99, 99, 7] pass 7 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 1, 6, 99, 99, 7] pass 8 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 1, 6, 99, 99, 7] pass 9 [1, 6, 2, 2, 7, 1, 6, 99, 99, 7] [1, 1, 6, 99, 99, 7] splice 6, 4 [1, 1, 6, 99, 99, 7]

The second splice at pass 9 has an offset of 6, but the last element of @copy is at index 5. Pass 4 spliced off 4 elements, so you want offset 2 here (6 - 4).

This does what you want:

#!/usr/bin/perl use warnings; use strict; use Data::Dump; ######## my $aref = [1, 6, 2, 2, 7, 1, 6, 99, 99, 7]; my $flag = 0; my $i = 1; my $sixindex = 0; my $spliced = 0; my @copy = @$aref; if (scalar(@$aref) >= 2) { foreach my $x (0..$#{$aref}) { print "pass $x\n"; dd $aref; dd \@copy; if (defined($aref->[$x])) { if ($aref->[$x] == 6) { $flag = 1; $sixindex = $x; next; } if ($flag) { unless ($aref->[$x] == 7) { $i++; next; } elsif ($aref->[$x] == 7 ) { print "splice ",$sixindex-$spliced, " ",($i+1 +),"\n"; splice(@copy, $sixindex-$spliced, $i + 1); $spliced += $i + 1; $flag = 0; $i = 1; $sixindex = 0; next; } } } } } dd \@copy;

All that indexing stuff is only necessary because you make a copy of the array and delete the ignored elements later. Is that a requirement of the homework? If not, you could drop all that index counting and track keeping stuff, and just push the elements not to be ignored onto @copy :

#!/usr/bin/perl use warnings; use strict; use Data::Dump; ######## my $aref = [1, 6, 2, 2, 7, 1, 6, 99, 99, 7]; my $flag = 0; my @copy; if (scalar(@$aref) >= 2) { foreach my $x (@$aref) { dd $aref; dd \@copy; if (defined($x)) { if ($x == 6) { $flag = 1; next; } if ($flag) { next unless $x == 7; $flag = 0; next; } print "push \@copy,$x\n"; push @copy, $x; } } } dd \@copy;

The only helper variable left now is $flag. But Perl has the ".." range operator which acts like a flip-flop, and as such has the $flag boolean built-in. Using that:

#!/usr/bin/perl use warnings; use strict; use Data::Dump; ######## my $aref = [1, 6, 2, 2, 7, 1, 6, 99, 99, 7]; my $flag = 0; my @copy; if (scalar(@$aref) >= 2) { foreach my $x (@$aref) { dd $aref; dd \@copy; if (defined($x)) { if ($x == 6 .. $x == 7) { next; } print "push \@copy,$x\n"; push @copy, $x; } } } dd \@copy;

Condense that a bit further, and you have tybalt89's solution.

perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

Replies are listed 'Best First'.
Re^2: Ignore a range of numbers in a List
by pr33 (Scribe) on Jun 25, 2017 at 17:58 UTC

    Thanks shmem. I have realized the problem with my code initially and couldn't think of a way to fix the offset going outside of the @copy array

    The second solution using array values is precise and clear . I have tried the code and it yields right results for all the test iterations.

      Alternatively, you can just use splice with a negative offset to remove elements from the end

      #!perl use strict; use warnings; while (<DATA>){ chomp; my $aref = [ split /\s+/,$_ ]; print join ' ', 'Original Array:', @$aref,"\n"; my $start; my @copy=(); my $i=0; for (@$aref){ push @copy,$_; if ($_ == 6){ $start = $i unless defined $start; } elsif (defined $start && $_ == 7){ splice @copy, $start-$i-1; $start = undef; } ++$i; } print join ' ','Results:',@copy,"\n"; } __DATA__ 1 6 2 2 7 1 6 99 99 7 1 2 2 1 1 6 7 2 1 6 2 2 7 1 6 99 99 7 2 7 6 2 6 7 2 7 1 6 7 7 2 7 6 2 6 2 7 6 7 1 6 7 7 6 8 1 6 7
      poj

      There's another way to do it: use decreasing indices and iterate from the end to the beginning. This keeps the arrays aligned after splice.

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1193496]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2024-04-23 12:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found