Reputation: 27
I have this sample text which I would like to access one of the multiple lines from a single array element.
Student 1:
Math 83
Chemistry 60
Physics 75
Student 2:
Math 69
Chemistry 76
Physics 73
Art A-
My script for storing multiple lines to a single array element is as following:
use strict;
use warnings;
open my $fh, '<', 'Text1' or die "Could not open file to read:$!";
my $file = do { local $/; <$fh> };
my @a = split /\n\n/, $file;
close $fh;
print "First array element is $a[0]\n";
print "Second array element is $a[1]\n";
The output is
First array element is Student 1:
Math 83
Chemistry 60
Physics 75
Second array element is Student 2:
Math 69
Chemistry 76
Physics 73
Art A-
Is there a better way for me to access and grab one of the multiple lines in first or 2nd element of the array for further usage? i.e, I need Math score
from each student.
Here is what I come up so far, to join the first element of the array and split them again. Thanks in advance.
use strict;
use warnings;
open my $fh, '<', 'Text1' or die "Could not open file to read:$!";
my $file = do { local $/; <$fh> };
my @a = split /\n\n/, $file;
close $fh;
print "First array element is $a[0]\n";
print "Second array element is $a[1]\n";
my $str=join('',$a[0]);
my @score1 = split('\n',$str);
$str=join('',$a[1]);
my @score2 = split('\n',$str);
print "Student 1 : $score1[1]\n";
print "Student 2 : $score2[1]\n";
Upvotes: 0
Views: 219
Reputation: 98388
Your read and split can be simplified to using readline's paragraph mode:
my @student = do { local $/ = ""; <$fh> };
I would be inclined to break each student up into a hash:
my @student = map {
my ($student, $scores) = /\A(.*):\n(.*)/s;
{
'Name' => $student,
split ' ', $scores
}
} do { local $/ = ""; <$fh> };
for my $student_number (0..1) {
print "Name: $student[$student_number]{Name} Math Score: $student[$student_number]{Math}\n";
}
If there is no blank line between students:
my @student;
my $current_student;
while ( my $line = <$fh> ) {
if ( my ($name) = $line =~ /^(.*):/ ) {
$current_student = { 'Name' => $name };
$line =~ s/^.*://;
push @student, $current_student;
}
my @scores = split ' ', $line;
while ( my ($subject, $score) = splice(@scores, 0, 2) ) {
$current_student->{$subject} = $score;
}
}
(A subject has to be on the same line as its score.)
Upvotes: 3
Reputation: 6573
Instead of 'slurping' the entire file, you could read in one 'paragraph' at a time by setting $/
to ""
. I would have used a hash instead of @score1
and @score2
. Then you could address the sought math score by using Math as a key. It would look something like this-
#!/usr/bin/perl
use strict;
use warnings;
my @grades;
{
local $/ = "";
while (<DATA>) {
push @grades, { split };
}
}
for my $href (@grades) {
print "student: $href->{Student} Math: $href->{Math}\n";
}
Output-
student: 1: Math: 83
student: 2: Math: 69
Upvotes: 3