Reputation: 7846
I have the below code snippet. I need to insert a grep
command in the appropriate place to find only grades between 80 and 89 and store them in a separate array called @GradeB
. I've tried using @GradeB = grep("8[0-9]", @Grades);
, but that puts everything into @GradeB
. Where am I going wrong to get only grades between 80-89 into @GradeB
? For full disclosure, this is is homework, but I am allowed to use any and all resources available to me.
@Grades = ("Name: Shemp Grade: 82",
"Name: Curly Grade: 62",
"Name: Curly Joe Grade: 58",
"Name: Joe Grade: 50",
"Name: Moe Grade: 88",
"Name: Larry Grade: 82");
# grep command here
print join("\n", @GradeB);
Upvotes: 0
Views: 575
Reputation: 24063
grep
returns each item in a list for which the expression evaluates to true. The expression
"8[0-9]"
is a string, and it always evaluates to true. You probably meant to use a regular expression instead:
my @b_grades = grep /Grade: 8[0-9]$/, @grades;
# Alternately, my @b_grades = grep { /Grade: 8[0-9]$/ } @grades;
Note that I've used a more specific regex than just /8[0-9]/
, which would match things like:
Name: Inmate 12789132 Grade: 12
This approach works, but isn't very flexible. As Borodin points out in the comments, changing the regex to match scores between, say, 79 and 88 is difficult. It would be better to extract the scores so we can do numerical comparisons:
my @b_grades = grep {
if (/Grade: (\d+)$/) {
$1 if ($1 >= 80 && $1 < 90);
}
} @grades;
This is just a different way of writing Borodin's solution.
Note that an array is not the best choice of data structure for this. When you have a list of key/value pairs, think "hash." In this case, you can use names as keys and grades as values:
my %grades = (
Shemp => 82,
Curly => 62,
'Curly Joe' => 58,
Joe => 50,
Moe => 88,
Larry => 82
);
Note that quotes are optional around keys that only consist of letters, digits, and underscores. To access the values in the hash, use the aptly-named values
function:
my @grades = values %grades;
Using grep
as before to get all the B's:
my @b_grades = grep { $_ >= 80 && $_ < 90 } values %grades;
print join ',', @b_grades;
# 88,82,82
This gives us a list of grades, but now we have no idea who they belong to. For that, we need to use keys
, which, strangely enough, returns a list of all the keys in our hash:
my @b_students = grep { $grades{$_} >= 80 && $grades{$_} < 90 } keys %grades;
print "Name: $_\tGrade: $grades{$_}\n" for @b_students;
# Name: Moe Grade: 88
# Name: Larry Grade: 82
# Name: Shemp Grade: 82
Upvotes: 1
Reputation: 126722
It is best not to use capitals for lexical variable names.
This solution works by extracting the string of digits that follow Grade:
and comparing it with the specified range.
use strict;
use warnings;
my @grades = (
"Name: Shemp Grade: 82",
"Name: Curly Grade: 62",
"Name: Curly Joe Grade: 58",
"Name: Joe Grade: 50",
"Name: Moe Grade: 88",
"Name: Larry Grade: 82",
);
print "$_\n" for grep {
/grade\s*:\s*(\d+)/i and $1 >= 80 and $1 < 90;
} @grades;
output
Name: Shemp Grade: 82
Name: Moe Grade: 88
Name: Larry Grade: 82
Upvotes: 2
Reputation: 19204
Take look at perldoc for grep
:
grep BLOCK LIST
grep EXPR,LIST
Grep evaluates BLOCK
or EXPR
for every element of LIST
and returns list composed of elements for which BLOCK
or EXPR
evaluate to true value. As you specify string "8[0-9]"
, which is always true, every list element is returned.
You need to pass regular expression as EXPR
:
@GradeB = grep /8[0-9]/, @Grades;
Upvotes: 2
Reputation: 36262
You can use a combination of map()
and grep()
. The first one creates an arrayref to keep the whole line and the last number in it, the grep()
compares them, and last map()
extracts the whole line of those which matched:
#!/usr/bin/env perl
use warnings;
use strict;
my @Grades = ("Name: Shemp Grade: 82",
"Name: Curly Grade: 62",
"Name: Curly Joe Grade: 58",
"Name: Joe Grade: 50",
"Name: Moe Grade: 88",
"Name: Larry Grade: 82");
# grep command here
my @GradeB =
map { $_->[0] }
grep { $_->[1] >= 80 and $_->[1] <= 89 }
map { [$_, (split)[-1]] } @Grades;
print join("\n", @GradeB);
It yields:
Name: Shemp Grade: 82
Name: Moe Grade: 88
Name: Larry Grade: 82
Upvotes: 1