1

So I'm getting input from STDIN like:

1 2 3
4 5 6
7 6 3

4 3 2
2 3 5
2 5 1

Blank lines separate the matrices, so the above input should create two multi-dimensional arrays...I know how to create one (code below), but how do I create multiple ones depending on how many blank lines the user inputs?

I won't know how many arrays the user wants to create so how can I dynamically create arrays depending on the blank lines in the user input?

my @arrayrefs;


while(<>)
{

chomp;

    my @data = split(/\s+/,$_);
    push @arrayrefs, \@data;
}


for $ref (@arrayrefs){
    print "[@$ref] \n";
}

3 Answers 3

1

With your data, I'd say using paragraph mode for the input stream would be a good idea. That is basically setting the input record separator $/ to "\n\n", but in this case we will use "", which is a bit more magical in that it is flexible with extra blank lines.

use strict;
use warnings;
use Data::Dumper;

sub parse_data {
    my @matrix = map { [ split / / ] } split /\n/, shift;
    return \@matrix;
}

my @array;
$/ = "";
while (<>) {
    push @array, parse_data($_);
}
print Dumper \@array;

The map/split statement is not as complex as it looks. Reading from right to left:

  • shift an argument from the argument list @_
  • split that argument on newline
  • take each those (i.e. map them) split arguments and split them again on space, and put the result inside an anonymous array, using brackets [ ].

All done.

Sign up to request clarification or add additional context in comments.

7 Comments

Alternatively: my @array = map { parse_data( $_ ) } <>;
+1. You could change the body of parse_data to just [map { [ split / / ] } split /\n/, shift] without losing readability as well.
@flesk I could, but this way, I leave the name of the variable as a hint as to what is returned. Also, I feel that an explicit return statement is easier to understand.
@flesk : "without losing readability"? There's an awful lot going on in that one line and should be subbified IMO
@Zaid: I agree about that, but in my opinion this solution is already half-golfed, and requires some mental acrobatics to grasp without the provided explanation anyway. But then again, with the change I suggested, why not place it directly into the map you suggested I guess. It's a slippery slope.
|
0

It won't win any Code Golf competition, but it does seem to work:

$ cat data
1 2 3
4 5 6
7 6 3

4 3 2
2 3 5
2 5 1
$ cat xx.pl
#!/usr/bin/env perl
use strict;
use warnings;

my @matrices;
my @matrix;

sub print_matrices()
{
    print "Matrix dump\n";
    foreach my $mref (@matrices)
    {
        foreach my $rref (@{$mref})
        {
            foreach my $num (@{$rref})
            {
                print " $num";
            }
            print "\n";
        }
        print "\n";
    }
}

while(<>)
{
    chomp;
    if ($_ eq "")
    {
        my(@result) = @matrix;
        push @matrices, \@result;
        @matrix = ();
    }
    else
    {
        my @row = split(/\s+/,$_);
        push @matrix, \@row;
    }
}

# In case the last line of the file is not a blank line
if (scalar(@matrix) != 0)
{
        my(@result) = @matrix;
        push @matrices, \@result;
        @matrix = ();
}

print_matrices();
$ perl xx.pl data
Matrix dump
 1 2 3
 4 5 6
 7 6 3

 4 3 2
 2 3 5
 2 5 1

$

Comments

0
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @arrays = [];

while (<>) {
    if (my @array = /(\d+)/g) {
        push $arrays[$#arrays], \@array; 
    } else {
        push @arrays, [];   
    }
}

$Data::Dumper::Indent = 0;
printf("%s\n", Dumper $arrays[0]);
printf("%s\n", Dumper $arrays[1]);

Output:

$VAR1 = [['1','2','3'],['4','5','6'],['7','6','3']];
$VAR1 = [['4','3','2'],['2','3','5'],['2','5','1']];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.