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

Hello monks,

look below data:
my @dd = qw/AA JJ CC M 1 1 3 4 D JJ 1 1 D M 3 3 4 D C M 3 3 3 D P Z/;
I'd like to extract all data in M and D(including M & D), and group them respectively like
my @res1 = qw/M 1 1 3 4 D/; my @res2 = qw/M 3 3 4 D/; my @res3 = qw/M 3 3 3 D/;
before I manually(ugly)treat them by a loop or recursion, I'd like to ask monks if any module treat this problem.

Thanks in advance.

Replies are listed 'Best First'.
Re: how extract and group data in a array
by kcott (Archbishop) on Feb 21, 2017 at 06:10 UTC

    I'm not aware of any module to do this.

    I don't see how "recursion" would help you here.

    There's no need for an "ugly" loop. Just iterate your array; use a boolean flag to indicate if elements are in the wanted group.

    #!/usr/bin/env perl -l use strict; use warnings; my @dd = qw/AA JJ CC M 1 1 3 4 D JJ 1 1 D M 3 3 4 D C M 3 3 3 D P Z/; my $in_group = 0; my (@group, @all_groups); for (@dd) { $in_group = 1 if $_ eq 'M'; next unless $in_group; push @group, $_; if ($_ eq 'D') { push @all_groups, [ @group ]; @group = (); $in_group = 0; } } print "@$_" for @all_groups;

    Output:

    M 1 1 3 4 D M 3 3 4 D M 3 3 3 D

    — Ken

      Nice. For the record, this can be simplified a little using Perl’s range operator in static context:

      use strict; use warnings; my @dd = qw/AA JJ CC M 1 1 3 4 D JJ 1 1 D M 3 3 4 D C M 3 3 3 D/; my @group; for (@dd) { if ($_ eq 'M' .. $_ eq 'D') # or: if (/^M$/ .. /^D$/) { push @group, $_; } elsif (@group) { print join(' ', @group), "\n"; @group = (); } } print join(' ', @group), "\n" if @group;

      Output:

      17:41 >perl 1752_SoPW.pl M 1 1 3 4 D M 3 3 4 D M 3 3 3 D 17:42 >

      Hope that’s of interest,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      yeah, your way is the first into my mind, set status variable, store data into an array etc. but since the data in array is a bit like html/xml, I thought someone would write module to do this.....
        "... but since the data in array is a bit like html/xml, I thought someone would write module to do this....."

        If @dd was only intended as example data, and your real data is HTML or XML, then there are modules for that (which would probably be a better choice than reinventing the wheel and writing your own parsing code). Try http://search.cpan.org/ and look for modules in the HTML:: or XML:: namespaces.

        — Ken

Re: how extract and group data in a array
by choroba (Cardinal) on Feb 21, 2017 at 06:23 UTC
    Instead of creating three arrays, you can create an array of arrays to store the results.

    To show TIMTOWTDI, I tried to play with a dynamic dispatch table:

    #!/usr/bin/perl use strict; use warnings; my @dd = qw/AA JJ CC M 1 1 3 4 D JJ 1 1 D M 3 3 4 D C M 3 3 3 D P Z/; my @results; my %dispatch = ( M => \&start ); sub empty {} sub store { push @{ $results[-1] }, $_ } sub start { %dispatch = ( D => \&stop ); push @results, []; # Start a new group. return \&store # Store the next elements. } sub stop { %dispatch = ( M => \&start ); store(); return \&empty # Stop storing the elements. } my $on_each = \&empty; for (@dd) { my $change = $dispatch{$_}; $on_each = $change->($_) if $change; $on_each->($_); } use Data::Dumper; print Dumper \@results;
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: how extract and group data in a array
by tybalt89 (Monsignor) on Feb 21, 2017 at 10:05 UTC

    It's just a one-liner...

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1182397 use strict; use warnings; my @dd = qw/AA JJ CC M 1 1 3 4 D JJ 1 1 D M 3 3 4 D C M 3 3 3 D P Z/; my @results = map [ split ], "@dd" =~ /\bM\b.*?\bD\b/g; use Data::Dumper; print Dumper \@results;
Re: how extract and group data in a array
by GrandFather (Saint) on Feb 21, 2017 at 06:08 UTC

    Looks like you want a regular expression to do the work for you. I suggest you take a look at perlretut for a start.

    You repeated use of arrays where you should be using scalars (my @dd; instead of my $dd;) suggest you are not very familiar with Perl so you may get some mileage out of reading through perlintro too.

    When you have put some code together to try, and if you should happen to have trouble making it work, come back for some guidance.

    Update: must be time for glasses! I'm sure I saw qq/.../. Sigh. Disregard the comments above.

    Premature optimization is the root of all job security
Re: how extract and group data in a array
by johngg (Canon) on Feb 21, 2017 at 23:03 UTC

    I used the range operator approach like Athanasius but, to avoid keeping track of state, inside a grep feeding into a join with nuls then a couple of splits, one breaking the string into chunks between the 'D' and the 'M', the other inside a map breaking each chunk into an array ref.

    use strict; use warnings; use Data::Dumper; my @dd = qw{ AA JJ CC M 1 1 3 4 D JJ 1 1 D M 3 3 4 D C M 3 3 3 D P Z +}; my @AoA = map { [ split m{\0} ] } split m{(?<=\0D)\0(?=M\0)}, join qq{\0}, grep { m{^M$} .. m{^D$} } @dd; print Data::Dumper->Dumpxs( [ \ @AoA ], [ qw{ *AoA } ] );

    The output.

    @AoA = ( [ 'M', '1', '1', '3', '4', 'D' ], [ 'M', '3', '3', '4', 'D' ], [ 'M', '3', '3', '3', 'D' ] );

    A bit convoluted I suppose.

    Cheers,

    JohnGG