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

Hi Monks! I have a question.

My text looks like

>James >40 >James >35 >James >26 >James >15
How can I convert this text into an array format which looks like James = [40, 35, 26,15] using Perl?

Replies are listed 'Best First'.
Re: Creating an array from text in perl
by choroba (Cardinal) on May 27, 2021 at 18:57 UTC
    It's unclear what you're asking. It seems you want the numbers to become elements of the array, but what about James? Are there any other names in your input?

    Maybe you rather need a hash of arrays, HoA, using the names as the keys and arrays of numbers as values?

    #!/usr/bin/perl use warnings; use strict; my %hash; my $name; while (<DATA>) { chomp; if ($. % 2) { # Even lines. $name = $_; } else { push @{ $hash{$name} }, $_; } } use Data::Dumper; print Dumper \%hash; __DATA__ James 40 Philip 12 James 35 James 26 James 15 Philip 27
    Output:
    $VAR1 = { 'James' => [ '40', '35', '26', '15' ], 'Philip' => [ '12', '27' ] };
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Yes that is the exact output I was looking for. Thanks for your time!
Re: Creating an array from text in perl
by GrandFather (Saint) on May 27, 2021 at 23:42 UTC

    A little closer to production code by opening a "file" and checking for unexpected data:

    use strict; use warnings; use Data::Dumper; my $testData = <<DATA; >James >40 >James >35 >James >26 >James >15 DATA open my $fin, '<', \$testData or die "Can't open file: $!\n"; my %people; my $lastPerson; while (defined (my $line = <$fin>)) { chomp $line; if ($line =~ /^>(\d+)$/) { die "Unexpected data order: '$line'\n" if !defined $lastPerson +; push @{$people{$lastPerson}}, $1; next; } if ($line =~ /^>(\w+)$/) { $lastPerson = $1; next; } warn "Don't know how to process '$line'\n"; } print Dumper(\%people);

    Prints:

    $VAR1 = { 'James' => [ '40', '35', '26', '15' ] };
    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Creating an array from text in perl
by Tux (Canon) on May 28, 2021 at 12:00 UTC

    Looks like homework, but anyway. My stab is a little more defensive and allows multiple (0 .. n) values per key

    use Data::Peek; my %d; while (<DATA>) { s/^\s*>?\s*(.*?)[\s\r\n]*\z/$1/; m/^(\d+)$/ ? push @{$d{$a}} => $1 : ($a = $_); } DDumper \%d; __END__ >James >40 >James >35 >James >26 >James >15 James 10 >12 >Philip 10 4 >5 Philip James Philip 18

    ->

    { James => [ '40', '35', '26', '15', '10', '12' ], Philip => [ '10', '4', '5', '18' ] }

    Enjoy, Have FUN! H.Merijn
Re: Creating an array from text in perl
by harangzsolt33 (Deacon) on May 27, 2021 at 22:44 UTC
    Here is another solution. There are probably a million ways to do this, so...

    #!/usr/bin/perl -w use strict; use warnings; my $TEXT = <<'END'; >James >40 >James >4 >John >35 >James >26 >John >31 >James >15 >Pete END $TEXT =~ tr|a-zA-Z0-9||cd; # Remove everything except letters a +nd numbers my @ARRAY = SplitNumbers($TEXT); # Split numbers vs letters if (@ARRAY & 1) { pop(@ARRAY); } # Remove last element if it has no n +umber following it. my %HASH; # This is used as a global here for (my $i = 0; $i < @ARRAY; $i+=2) { if (exists($HASH{$ARRAY[$i]})) { $HASH{$ARRAY[$i]} .= ', '; } $HASH{$ARRAY[$i]} .= $ARRAY[$i+1]; } print GetList('James'); print GetList('John'); print GetList('Pete'); print GetList('Bob'); exit; ################################################## # Returns the named list in nicely formatted way. # # Usage: STRING = GetList(NAME) # sub GetList { @_ or return ''; my $NAME = shift; # Get first argument, which is the 'NAME' return "\n $NAME = [" . (exists($HASH{$NAME}) ? $HASH{$NAME} : '') + . "]\n"; } ################################################## # # Splits a string along numbers and returns an # array of alternating numbers and text. # Usage: ARRAY = SplitNumbers(STRING) # # Example: SplitNumbers('abc45tt-35203.19') -> ["abc", 45, "tt-", 3520 +3, ".", 19] # sub SplitNumbers { defined $_[0] or return (); my ($PTR, $PREV, $LEN, $TYPE, @A) = (0, -1, length($_[0])); $LEN or return (); # Possible values for $PREV: -1=Uninitialized 0=NUMBER 1=TEXT for (my $i = 0; $i < $LEN; $i++) { $TYPE = vec($_[0], $i, 8); $TYPE = $TYPE < 48 || $TYPE > 57; # Is it a number? if ($PREV == !$TYPE) # Same as before? { push(@A, substr($_[0], $PTR, $i-$PTR)); $PTR = $i; } $PREV = $TYPE; } push(@A, substr($_[0], $PTR)); # Process last chunk return @A; } ##################################################

    This code outputs the following:

    James = [40, 4, 26, 15] John = [35, 31] Pete = [] Bob = []