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

I have the following code which generates a specific output.
my @result = (`cmd to get result`) ; foreach $result (@result) { @streams = ; @spaces = ; }
The command to get result has the following output
ws.abc.dsfsfsfwerfrwef std 13232 ws.dfsdferferfregregrgr std 99868 Y ws.abc.asddwefewfewfewf std 45345 fwfrwfrefergegregerefds std 36754 Y ws.abc.fferfergregrfreg std 45435
I would like to get the 1st word (before space) and which has "Y" at the ending to an array @streams and for rest of lines only 1st word (before space) to array @spaces like shown below.
@streams=(fwfrwfrefergegregerefds, ws.dfsdferferfregregrgr)
@spaces=(ws.abc.dsfsfsfwerfrwef, ws.abc.asddwefewfewfewf, ws.abc.fferfergregrfreg)
How can I achieve it?

Replies are listed 'Best First'.
Re: Perl : Split/Regex
by AppleFritter (Vicar) on Sep 03, 2014 at 21:09 UTC

    Use split to split your $result on whitespace, and push to the right array depending on whether you're seeing a "Y":

    foreach my $result (@result) { my @fields = split /\s+/, $result; if($fields[3] // "" eq "Y") { push @streams, $fields[0]; } else { push @spaces, $fields[0]; } }

    A note on the // "" bit: $fields[3] may be undefined if your $result didn't have enough fields, so I'm using the defined-or operator there to avoid spurious warnings ("Use of uninitialized value $fields[3] in string eq at 1099476.pl line 21").

      Since the OP mentions that the "Y" will be at the end, why not use a [ -1 ] subscript to avoid the "defined" complication? You could also use a single push with the conditional and target arrays in a ternary. Some may find this less readable than the if ... else ... but I prefer it for simple "push to this or that depending" situations.

      $ perl -Mstrict -Mwarnings -E ' open my $inFH, q{<}, \ <<EOD or die $!; ws.abc.dsfsfsfwerfrwef std 13232 ws.dfsdferferfregregrgr std 99868 Y ws.abc.asddwefewfewfewf std 45345 fwfrwfrefergegregerefds std 36754 Y ws.abc.fferfergregrfreg std 45435 EOD my @streams; my @spaces; while ( <$inFH> ) { my @flds = split; push @{ $flds[ -1 ] eq q{Y} ? \ @streams : \ @spaces }, $flds[ 0 ]; } say qq{@streams}; say qq{@spaces};' ws.dfsdferferfregregrgr fwfrwfrefergegregerefds ws.abc.dsfsfsfwerfrwef ws.abc.asddwefewfewfewf ws.abc.fferfergregrfreg $

      I hope this is of interest.

      Cheers,

      JohnGG

        Since the OP mentions that the "Y" will be at the end, why not use a [ -1 ] subscript to avoid the "defined" complication?

        That works, but what if you just so happen to have a "Y" in the third field? The OP's example lines only have numbers, granted, but I didn't want to assume too much about how his/her data is structured.

        You could also use a single push with the conditional and target arrays in a ternary. Some may find this less readable than the if ... else ... but I prefer it for simple "push to this or that depending" situations.

        Ah, yes, that's a good point. I was trying that, actually; it didn't work ("Not an ARRAY reference at ..."), but it didn't occur to me to wrap the whole shebang in a @{ }. OTOH, between that and the need to take references to the arrays you want to push to, it is indeed on the cryptic side.

        Nevertheless, I learned something new. Thank you for enlightening me, brother!

        The push reads better without the obfuscating ref/deref stuff:

        push (($flds[-1] eq 'Y' ? @streams : @spaces), $flds[0]);

        Update: Ok, so that was a fail - struck

        Perl is the programming world's equivalent of English
Re: Perl : Split/Regex
by AnomalousMonk (Archbishop) on Sep 04, 2014 at 00:27 UTC

    Here's a slight variation on the three-fields-versus-four approach: if there are four fields, the fourth must be 'Y', which is true. (I use unshift instead of push for the  @streams array because that gives the ordering of elements shown in the OPed example, which I take to be specificatory.)

    c:\@Work\Perl>perl -wMstrict -MData::Dump -le "my (@streams, @spaces); ;; for my $result ( 'ws.abc.dsfsfsfwerfrwef std 13232', 'ws.dfsdferferfregregrgr std 99868 Y', 'ws.abc.asddwefewfewfewf std 45345', 'fwfrwfrefergegregerefds std 36754 Y', 'ws.abc.fferfergregrfreg std 45435', ) { my ($first, undef, undef, $fourth) = split m{ \s+ }xms, $result; if ($fourth) { unshift @streams, $first; } else { push @spaces, $first; } } ;; dd \@streams; dd \@spaces; " ["fwfrwfrefergegregerefds", "ws.dfsdferferfregregrgr"] [ "ws.abc.dsfsfsfwerfrwef", "ws.abc.asddwefewfewfewf", "ws.abc.fferfergregrfreg", ]

    Update: One could also use the simple test  @fields == 4 if split-ing to an array.

Re: Perl : Split/Regex
by hdb (Monsignor) on Sep 04, 2014 at 06:05 UTC

    If performance is not your utmost concern, I would use two grep statements to filter out lines with and without Y at the end. It would the look like this:

    use strict; use warnings; my @result = <DATA>; my @streams = map /^(\S+)/, grep /\sY$/, @result; my @spaces = map /^(\S+)/, grep !/\sY$/, @result; print "streams: @streams\n"; print "spaces: @spaces\n"; __DATA__ ws.abc.dsfsfsfwerfrwef std 13232 ws.dfsdferferfregregrgr std 99868 Y ws.abc.asddwefewfewfewf std 45345 fwfrwfrefergegregerefds std 36754 Y ws.abc.fferfergregrfreg std 45435

    And if you are concerned about the three fields versus four fields issue, you could modify the condition in the grep statement accordingly.

Re: Perl : Split/Regex
by 2teez (Vicar) on Sep 03, 2014 at 22:55 UTC

    Or just twisting the "if" statement of AppleFritter suggestion a bit like this:

    if($fields[-1] eq 'Y'){ ...
    there was no longer need for the bit // "" in the if statement. Just a timtoday!
    for my $result (@results) { my @fields = split /\s+/, $result; if ( $fields[-1] eq 'Y' ) { push @streams, $fields[0]; } else { push @spaces, $fields[0]; } }

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me