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

I am attempting to find the weighted grades for 5 people with each having 6 scores. I made subroutines (untested) to calculate each of the different weights. The dilemma I am having is that all of my names and scores are currently in one array. My original thinking was that I would put make an array for the names, and an array for each persons exams, quizes, and final exam. Then running the scores through the subroutine. The problem is that it makes me think that I am creating a lot of extra arrays for something that could be condensed. My array is in a predictable order (name, score,score,score,score,score,score,name.....) Is there a way to take the first 3 scores run them through a subroutine and then put the other scores through their subroutines as well while keeping them in that array? Or is this just wishful thinking?

#usr/bin/perl use strict; use warnings; use feature qw(say); use List::Util qw(sum); open IN,'<',"part3.csv" or die "Can't open input file 'part3.csv': $!\ +n"; my $x; my @studentnames; sub quiz { return (sum(@_) / 300) * .10; } sub exam { return (sum(@_) / 200) * .20; } sub final { return (sum(@_) / 100) * .30; } while ($x = <IN>){ if ($x =~ /^\w*\s\w*/){ push @studentnames, +(split/,/, $x); } } foreach (@studentnames){ print "$_ \n"; } close IN;

Replies are listed 'Best First'.
Re: Weighted averages
by Eily (Monsignor) on Jan 25, 2018 at 16:55 UTC

    I agree with thanos1983 that it looks like you're searching for some kind of nested data structure. Maybe you can try something and ask us how to improve it, or show us how you might expect the data to look like (but it would help if you understood how nested structures work for that). Anyway, there is a nice idiom to access elements in an array when each position has a special meaning, constant:

    use strict; use warnings; use feature qw(say); use constant { STUDENT => 0, FIRST_QUIZ => 1, LAST_QUIZ => 3, FIRST_EXAM => 4, LAST_EXAM => 5, FINAL => 6, }; while (<DATA>) { my @fields = split /,/, $_; say "Student:", $fields[STUDENT]; say "Quizzes:", join ", ", @fields[FIRST_QUIZ..LAST_QUIZ]; say "Exams:", join ", ", @fields[FIRST_EXAM..LAST_EXAM]; say "Final:", $fields[FINAL]; say "-----" } __DATA__ Allen Bailey,90,95,80,98,76,89 Carole Daily,9,9,8,9,7,8 Evan Fairly,50,75,10,82,64,79
    Student:Allen Bailey Quizzes:90, 95, 80 Exams:98, 76 Final:89 ----- Student:Carole Daily Quizzes:9, 9, 8 Exams:9, 7 Final:8 ----- Student:Evan Fairly Quizzes:50, 75, 10 Exams:82, 64 Final:79 -----
    Here I have used Slices (@ meaning several elements at a time, and a list inside the [ ] rather than a single value, but you can define FIRST_QUIZ, SECOND_QUIZ and so on and access each element one by one if it's simpler to you.

    Also in /\w*\s\w*/, the * means 0 or more. So that's "maybe a letter/digit or more, a space, maybe a letter/digit or more", in the end the condition is pretty much only "a space". This might work, but this doesn't look like much of a constraint. Maybe you want + instead of * ?

      I feel like this is a stupid question, but what part of the while loop is allowing it to know to start a new group. Student, quize,exam, final. How does it go about starting with student again? In constant student is set to zero, but the second student is in the 7th index and not 0. Maybe I am just not understanding how that works. My second question is about running that through a subroutine. If I wanted to run the quizes through my quiz subrotuine would it be as simple as:

      sub quiz { return (sum(@fields[FIRST_QUIZ..LAST_QUIZ])/ 300) * .10; }

      Ultimately I am trying to find the final grades for each student.

        The data is read line by line. So each new line you get a new iteration of the loop, a new array, which starts at 0 again.

        Using my code and your sub, you could just write: say "Weighted average: ", quiz(@fields[FIRST_QUIZ..LAST_QUIZ]) + exam(@fields[FIRST_EXAM..LAST_EXAM]) + final($fields[FINAL])

Re: Weighted averages
by thanos1983 (Parson) on Jan 25, 2018 at 16:26 UTC

    Hello drose2211,

    For my point of view why not to use HASHES OF HASHES? I think is the best solution for your problem.

    Sample of code:

    Regarding on how to process the data and store them read the doc on the link above, alternatively provide (a few lines) as a sample of your CSV file and we can help you.

    Update: There are many many ways of resolving your problem. For a quick proposed solution something like that could be done using HASHES OF ARRAYS and HASHES OF HASHES. You can make the code sorter and more efficient with minor modifications but this should be enough to get you started.

    Sample of input data, based on the sample that you provided it:

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

      I will take a look at the link, but here is a line from the file. All other lines are identical in format.

      Allen Bailey,90,95,80,98,76,89

        Hello again drose2211,

        I have updated my answer with sample of code and possible solution to your question.

        Hope this helps, BR.

        Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Weighted averages
by raymorris (Novice) on Jan 27, 2018 at 22:12 UTC
    The dilemma I am having is that all of my names and scores are currently in one array.
    That is indeed your problem. Let's fix that. In fact you have a bunch of students. To represent "a bunch of" we use an array: @students = (); Each student has a final exam grade and probably a student ID:
    @students = ( { 'id' => 123, 'final'=> 94 }, { 'id' => 321 'final'=> 90 } );
    Each student also has a bunch of quizzes. "A bunch of" is called an array, so:
    @students = ( { 'id' => 123, 'final'=> 94, 'quiz' => [ 88, 45, 91 ] }, { 'id' => 321, 'final'=> 90, 'quiz' => [ 81, 93, 90 ] } );

    Now that our Perl data structure accurately represents the real world, the code to manipulate it is straightforward.

    "Bad programmers worry about the code. Good programmers worry about data structures and their relationships." Linus Torvalds

    Note - the single quotes around the hash keys such as 'final' aren't required. That's just my personal preference for style, since barewords aren't good in *general* I don't like having something that *looks* like a bareword.