in reply to Ignore a range of numbers ina List

I added some test cases. I wasn't sure if using splice was an absolute requirement, so I didn't use it. Also, as a general rule, I try to avoid using indicies. Code using indicies tends to be more error prone due to the dreaded "off by one" error which even very experienced programmers are prone to make.

In the code below, once a 6 is seen, I keep the numbers on a stack so that I can use them later if no matching 7 is found. The scalar value of @stack also does double duty as the "seen a 6 - inside of a potential sequence flag". I think the logic here is clear albeit a bit wordy. However well spaced out, simple code tends to run very quickly and I don't consider a bunch of white space a "problem"

#!/usr/bin/perl use warnings; use strict; use Data::Dumper; #http://www.perlmonks.org/?node_id=1193467 my $aref = [1, 7, 6, 2, 2, 7, 1, 6, 99, 99,7,88, 7, 6,1,2,3]; my @result; my @stack = (); foreach my $candidate (@$aref) { if ($candidate == 6) # starting flag { push @stack,6; } elsif ($candidate == 7) #potential ending flag { if (@stack) { @stack=(); #throw away between 6, x, y, 7 } else { push @result, 7; # a singleton 7 was seen } } elsif (@stack) # inside of sequence starting with 6 { push @stack, $candidate; } else { push @result, $candidate; } } push @result, @stack if @stack; # unfinished sequence starting with 6? print Dumper \@result; __END__ prints: $VAR1 = [ 1, 7, 1, 88, 7, 6, 1, 2, 3 ];

Replies are listed 'Best First'.
Re^2: Ignore a range of numbers ina List
by AnomalousMonk (Archbishop) on Jun 25, 2017 at 07:04 UTC

    I was thinking along lines similar to Marshall:

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le "use constant { START => 6, STOP => 7, }; ;; my $aref = [ 6, 7, 1, 6, 8, 9, 7, 2, 6, 98, 99, 7, 3, 7, 4, 6, 5, ]; dd $aref; ;; my @final; my $maybe_truncate; ;; for my $element (@$aref) { if (defined $maybe_truncate) { if ($element == STOP) { $#final = $maybe_truncate; undef $maybe_truncate; next; } } else { if ($element == START) { $maybe_truncate = $#final; } } push @final, $element; } ;; dd $aref; dd \@final; " [6, 7, 1, 6, 8, 9, 7, 2, 6, 98, 99, 7, 3, 7, 4, 6, 5] [6, 7, 1, 6, 8, 9, 7, 2, 6, 98, 99, 7, 3, 7, 4, 6, 5] [1, 2, 3, 7, 4, 6, 5]
    I suspect this logic can be cleaned up significantly. I'd like get something approaching tybalt89's solution.


    Give a man a fish:  <%-{-{-{-<

Re^2: Ignore a range of numbers ina List
by pr33 (Scribe) on Jun 25, 2017 at 07:11 UTC

    All my tests have returned the right results with Marshall's code .

    $./ignore_6_to_7.pl Original Array : 1 6 2 2 7 1 6 99 99 7 Result: 1 1 ********** Original Array : 1 2 2 Result: 1 2 2 ********** Original Array : 1 1 6 7 2 Result: 1 1 2 ********** Original Array : 1 6 2 2 7 1 6 99 99 7 Result: 1 1 ********** Original Array : 2 7 6 2 6 7 2 7 Result: 2 7 2 7 ********** Original Array : 1 6 7 7 Result: 1 7 ********** Original Array : 2 7 6 2 6 2 7 Result: 2 7 ********** Original Array : 6 7 1 6 7 7 Result: 1 7 ********** Original Array : 6 8 1 6 7 Result: **********
      Hi pr33,

      Wow, your question certainly got the Monks working on lots of solutions!

      I recommend understanding every single program in this thread... Understand exactly how they work.

      I am curious if this was some sort of homework assignment or not?
      I am also curious about what other languages you know?

      I did not assume that this was homework for the simple reason that the beginner classes that I work with would not have even covered array indicies before an assignment like this would be given. You wouldn't be thinking in that direction because, the class wouldn't have even talked about it! Of course it could be that you are in a "bad class". In any case all the better to show some better ways!

      None of the code presented (except yours) uses splice() and array index. I hope that sends you a clear message! Normally use the Perl array iterators which do not depend upon some [$i] index value. Of course indicies can and should be used in some situations, but they should not be your first thought.

      My code perhaps appears at first glance to be "complicated" as compared to some of the more brief solutions. I will try to explain the thought process. Maybe other Monks can do that for their code also?

      I rejected at first thought any idea of splice() and index as being too complicated. Also your code did not require me to modify the input array "in place" - that means to me that I can use extra memory for the "solution".

      I started with a foreach loop over all of the input numbers. There are actually 4 conditions:

      • Something needs to happen if I see a "6"
      • Something needs to happen if I see a "7"
      I worked on those parts (ran the code) and made decisions about not needing a $flag and that @stack could serve that function.

      Then I coded:

      • Case where I am within a 6,x,yz,7 sequence
      • Case where I am not within such a sequence.
      There was some short back and forth to fine tune the singleton 7 idea, but there was a place for it within the 4 basic cases.

      I recommend looking at Laurent_R's solution here. It is shorter but still has the basic 4 different situations.

      Of course, "shorter, fewer lines" does not always mean "better" or even "faster". I tried to present some code for you that you could understand and modify if necessary to meet your needs.

        Thanks, Marshall for your recommendation.

        Well, as I said, I first thought that Marshall's idea of a solution was good, but since I felt that is was probably a bit complicated. I was hoping to make something simpler. As I said, I ended up doing independently something essentially similar (although written differently and using an additional $flag variable, which isn't really necessary, as Marshall has shown).

        Trying to simplify (or at least shorten) the code I tried to use a ternary conditional, something along these lines:

        push $flag ? @temp : @result, $num;
        But the compiler doesn't like this. Even adding parentheses does not seem to help.

        So that's why I next came to the idea of pushing the values to a variable containing a reference to either the @temp or the @result array, depending on whether we are in a 6..7 range or not. I think this is pretty clean and clear, and quite concise, but using references this way may be beyond the knowledge of a beginner (although the OP uses an array reference).

        Maybe other Monks can do that for their code also?

        Well, I have exposed why the OPs code failed, how to fix that, then steered towards a more perlish solution via something like Laurent_Rs solution (first one) arriving at tybalt89s version (with some decoration resembling the OP). Just trying to explain things a bit...

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      What about
      Original Array : 1 6 2 2 7 1 6 99 99 Result: ?

        Yeah, that's another big flaw in the OPs code: no handling of unspecified conditions. Without a closing 7, what should an opening 6 have done? Your browser is full of that - implicit close of tags at some place, lacking the closing tag. I don't even want to know how much code has been written to prevent blowing up on that.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re^2: Ignore a range of numbers ina List
by pr33 (Scribe) on Jun 25, 2017 at 06:34 UTC

    Thanks Marshall . The solution works . The other solution by tybalt89 also works, But I was looking for a more structured code similar to your's.