Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Loop Array - If $var is something write values until $var is something else

by maikelnight (Sexton)
on Sep 29, 2018 at 15:51 UTC ( [id://1223282]=perlquestion: print w/replies, xml ) Need Help??

maikelnight has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, beginner :-/ - i loop through an array and i want to give values out until the loop variable is something else. To be more clear:
foreach my $x (@cleared) { my $jobprofil = $x->{JobProfil}; if (defined $jobprofil){ print $jobprofil, "\n"; } else { unless ($x =~ m/^Something/){ print "~~Something~~", $x, "\n"; } } }
This prints me ~~Something~~HereOutput I tried to add:
else { unless ($x =~ m/^Something Else/){ print "~~Something Else~~", $x, "\n"; } }
But the result is not what i want. It prints:

~~Something Else~~HereOutput ~~Something~~HereOutput ~~Something~~HereOutput ~~Something~~HereOutput ~~Something~~HereOutput

How can i have my output printed like:

~~Something~~HereOutput ~~Something~~HereOutput ~~Something~~HereOutput ~~Something~~HereOutput ~~Something Else~~HereOutput ~~Something Else~~HereOutput ~~Something Else~~HereOutput ~~Something Else~~HereOutput

Replies are listed 'Best First'.
Re: Loop Array - If $var is something write values until $var is something else
by GrandFather (Saint) on Sep 29, 2018 at 23:32 UTC

    I'm not sure what your "could be removed" string in the output is supposed to denote, but assuming that output string could be removed, the following may provide some ideas:

    use strict; use warnings; my @cleared = ( 'JOB::HEREISASTRING', 'Something', 'StringA', 'StringB', 'StringC', 'StringD', 'Something Else', 'StringE', 'StringF', 'StringG', 'StringH ', 'JOB::HEREISANOTHERSTRING', 'Something', 'StringI', 'StringJ', 'StringK', 'StringL', 'Something Else', 'StringM', 'StringN', 'StringO', 'StringP ', ); my @result; my $prefix = '~~Something~~'; foreach my $x (@cleared) { if ($x =~ /JOB::(.*)/) { $prefix = ""; } elsif ($x =~ m/^Something Else/) { $prefix = "~~Something Else~~"; } elsif ($x =~ m/^Something/) { $prefix = "~~Something~~"; } print "$prefix$x\n"; }

    Prints:

    JOB::HEREISASTRING ~~Something~~Something ~~Something~~StringA ~~Something~~StringB ~~Something~~StringC ~~Something~~StringD ~~Something Else~~Something Else ~~Something Else~~StringE ~~Something Else~~StringF ~~Something Else~~StringG ~~Something Else~~StringH JOB::HEREISANOTHERSTRING ~~Something~~Something ~~Something~~StringI ~~Something~~StringJ ~~Something~~StringK ~~Something~~StringL ~~Something Else~~Something Else ~~Something Else~~StringM ~~Something Else~~StringN ~~Something Else~~StringO ~~Something Else~~StringP

    The trick is to use a "state" variable (in this case $prefix) to remember what state the parser is in. This is a trivial case of a state machine which can be used to simplify implementing many parsing and processing systems.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
      Dear All, thanks much for you input! Dear GrandFather, the state variable is what i was after and i thought in that direction as i said. thank you. it solved my issue. Big ups!
Re: Loop Array - If $var is something write values until $var is something else
by Marshall (Canon) on Sep 29, 2018 at 17:32 UTC
    Hi maikelnight!,
    First when you post a question here, the ideal situation is that you provide a completely runnable example including a sample of the data. That way I can just download the code into my Perl environment, push the "go button" and replicate exactly what you are seeing. update: Basically the easier you make it for the Monks to run your code, the more likely you are to get a prompt and good response. Right now I'd have to work my brain a bit to reverse engineer some data that would produce your results. Things are much better if I don't have to do that.

    Do you have use strict; use warnings;? That is important. It looks like @cleared is an AoA (Array of Array), i.e. a 2-D structure. This code: ($x =~ m/^Something Else/) won't work because $x is a reference to an array. You need $x->[someIndex]to get a string to compare against. I am surprised if what you have doesn't throw some kind of an error? Why don't you rename $x, $row_ref or something like that? $x is not very descriptive.

    This does look weird:

    unless ($x =~ m/^Something Else/){ print "~~Something Else~~", $x, "\n"; }
    That is the same as: print ~~Something Else~~ if $x is not Something Else , which is kinda weird.
    if ($x->[someIndex] !~ m/^Something Else/){}
    Does that help?

    Enclose the output in code tags so that we can see the line breaks.

      It looks like @cleared is an AoA

      The curly braces suggest to me that it might be an AoH instead.

      johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E ' my @AoH = ( { jobName => q{Director}, jobProfile => q{Three day week}, }, { jobName => q{Manager}, jobProfile => q{9to5}, }, ); foreach my $job ( @AoH ) { say $job; say $job->{ jobProfile }; }' HASH(0x562033e731e0) Three day week HASH(0x562033e92488) 9to5

      I agree though that the unless ($x =~ m/^Something Else/){ does look weird as it would seem to be trying to match against a stringified reference. I suspect that we are not seeing the whole story.

      Cheers,

      JohnGG

        I agree. I misread the fonts between { and [ without my reading glasses! My dev environment has larger fonts than my browser!
        In any event, these 2 code statements from the OP are inconsistent with the type of value of $x:
        my $jobprofil = $x->{JobProfil}; ...later this... unless ($x =~ m/^Something Else/){
        Something is wrong here. I am hoping that a full runnable code example with use strict; use warnings; will be very helpful.
Re: Loop Array - If $var is something write values until $var is something else
by AnomalousMonk (Archbishop) on Sep 29, 2018 at 19:32 UTC

    maikelnight:   Further to Marshall's post:   Please see Short, Self-Contained, Correct Example. The monks grow sullen and silent when you make them do a lot of work in order to give free advice.

    Others have noted that you don't seem to have warnings and strictures enabled. Let me repeat: Especially if you're a beginning Perler, always have the two statements
        use warnings;
        use strict;
    at the beginning of your script. See (and use!) warnings and strict.

    Finally, you seem confused about just what is in the  @cleared array; we certainly are. Using some kind of data dumper can bring much enlightenment. Popular are Data::Dumper::Dump() (which is core and so should already be loaded in your system), and Data::Dump::dd() (which I like better, but it's not core, so you may have to load it yourself). Use one or the other
        use Data::Dumper;
        ...
        print Dumper \@cleared;
    or
        use Data::Dump;
        ...
        dd \@cleared;
    and you may find yourself much further down the road to a working application!


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

      Sorry for confusing, should have removed the reference part as its not really important to my question. I removed it, use strict and warnings and now here is it:
      my @result; foreach my $x (@cleared) { if ($x =~ /JOB::(.*)/){ print $x, "\n"; } else { unless ($x =~ m/^Something/){ print "~~Something~~", $x, "\n"; } else { unless ($x =~ m/^Something Else/){ print "~~Something Else~~", $x, "\n"; } } } }
      Lets see the @cleared (Dump):
      $VAR1 = 'JOB::HEREISASTRING'; $VAR2 = 'Something'; $VAR3 = 'StringA'; $VAR4 = 'StringB'; $VAR5 = 'StringC'; $VAR6 = 'StringD'; $VAR7 = 'Something Else'; $VAR8 = 'StringE'; $VAR9 = 'StringF'; $VAR10 = 'StringG'; $VAR11 = 'StringH '; $VAR12 = 'JOB::HEREISANOTHERSTRING'; $VAR13 = 'Something'; $VAR14 = 'StringI'; $VAR15 = 'StringJ'; $VAR16 = 'StringK'; $VAR17 = 'StringL'; $VAR18 = 'Something Else'; $VAR19 = 'StringM'; $VAR20 = 'StringN'; $VAR21 = 'StringO'; $VAR22 = 'StringP ';
      Output:
      JOB::HEREISASTRING ~~Something Else~~Something ~~Something~~StringA ~~Something~~StringB ~~Something~~StringC ~~Something~~StringD ~~Something~~Something Else ~~Something~~StringE ~~Something~~StringF ~~Something~~StringG ~~Something~~StringH JOB::HEREISANOTHERSTRING ~~Something Else~~Something ~~Something~~StringI ~~Something~~StringJ ~~Something~~StringK ~~Something~~StringL ~~Something~~Something Else ~~Something~~StringM ~~Something~~StringN ~~Something~~StringO ~~Something~~StringP
      I wish output:
      JOB::HEREISASTRING ~~Something Else~~Something Else (could be removed) ~~Something~~StringA ~~Something~~StringB ~~Something~~StringC ~~Something~~StringD ~~Something Else~~Something Else (could be removed) ~~Something Else~~StringE ~~Something Else~~StringF ~~Something Else~~StringG ~~Something Else~~StringH JOB::HEREISANOTHERSTRING ~~Something Else~~Something Else (could be removed) ~~Something~~StringI ~~Something~~StringJ ~~Something~~StringK ~~Something~~StringL ~~Something Else~~Something Else (could be removed) ~~Something Else~~StringM ~~Something Else~~StringN ~~Something Else~~StringO ~~Something Else~~StringP
      In fact i want to tag my values from a start until a match occurs and tag it different and so on.... What comes to my mind is that with foreach loop variable $x changes and in the loop is again "Something"!?
        You seem to want the flip-flop operator. Ref: Range Operators in perlop. A "state variable" is not needed because the state is stored in the operator.
        ?type 1223291.pl use strict; use warnings; my @cleared = ( 'JOB::HEREISASTRING', 'Something', 'StringA', 'StringB', 'StringC', 'StringD', 'Something Else', 'StringE', 'StringF', 'StringG', 'StringH ', 'JOB::HEREISANOTHERSTRING', 'Something', 'StringI', 'StringJ', 'StringK', 'StringL', 'Something Else', 'StringM', 'StringN', 'StringO', 'StringP ', ); foreach (@cleared) { if (/JOB::(.*)/){ print $_, "\n"; next; } print '~~Something'; if ( !(/Something$/ ... /Something Else$/) or /Else/) { print ' Else'; } print "~~$_\n"; } ?perl 1223291.pl JOB::HEREISASTRING ~~Something~~Something ~~Something~~StringA ~~Something~~StringB ~~Something~~StringC ~~Something~~StringD ~~Something Else~~Something Else ~~Something Else~~StringE ~~Something Else~~StringF ~~Something Else~~StringG ~~Something Else~~StringH JOB::HEREISANOTHERSTRING ~~Something~~Something ~~Something~~StringI ~~Something~~StringJ ~~Something~~StringK ~~Something~~StringL ~~Something Else~~Something Else ~~Something Else~~StringM ~~Something Else~~StringN ~~Something Else~~StringO ~~Something Else~~StringP ?

        UPDATE: Added reference

        Bill
Re: Loop Array - If $var is something write values until $var is something else
by davido (Cardinal) on Sep 29, 2018 at 19:21 UTC

    So is it accurate that your datastructure looks something like this?

    my @cleared = ( 'Something', {JobProfil => undef}, {JobProfil => 1}, 'Something else that should match', 'This one should not match', );

    Why are there hashrefs in some elements and not in others? Possibly the first test you should be doing is checking if $x contains a reference, at each iteration. Otherwise, you'll be trying to dereference $x as a hashref when it's actually just a plain old string. This would run afoul of strict 'refs';.


    Dave

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1223282]
Approved by haukex
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-20 02:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found