Help implement the Perl task solution:

At the entrance to the program, information is given about the passing of examinations by students of the 9th grade of a certain secondary school. The first line reports the number of students N, which is not less than 10, but not more than 100, each of the following N lines has the following format: <Last name> <First name> <rating>, where <Last Name> is a line consisting of no more than 20 characters, <Name> - a string consisting of no more than 15 characters, <estimates> - three integers separated by a space, corresponding to the estimates of a five-point system. <Last Name> and <First Name>, as well as <First Name> and <assessment> are separated by a single space. Example of an input line: Ivanov Peter 4 5 3 You need to write a program as efficient as possible (indicate the version of the programming language used, for example, Borland Pascal 7.0), which will display the names and names of the three worst average students. If among the rest there are students who have scored the same average score as one of the three worst, then their names and surnames should be derived.

I am stuck at work with the lines themselves, I understand that it is necessary to use hashes, where the first and last names will be keys, and the average score value, but I can’t think how to do this with a minimum of gestures. The function to calculate the average score:

sub GPA { my @balls = @_ ; my $sum = 0; foreach my $item(@balls){ $sum += $item; } return $sum/scalar @balls; } 
  • Is it possible to solve the problem not in Perl, but in PHP or C ++, for example? If yes, then I will decide) - AseN
  • Alas, but I need it on Perl :) - Error
  • Sorry ... I don’t own Perl `.... - AseN
  • I almost am not familiar with a pearl, but unless not such algorithm? when entering data for each student, we split lines by a space character, i.e. we get an array of the form $ arr ("Last Name", "First Name", "4", "3", "5"); for each student. immediately assigning the value of the average ball to a certain local array, the key is using the link Name Last Name $ localArr [$ arr [1]. ' '. $ arr [2]] = average ($ arr [3], $ arr [4], $ arr [5]); then we sort this array and display the result. Code examples on pkhp. I think for the knowledgeable perl to translate work will not be - ikoolik
  • And yet how can I not solve the problem with the encoding, on ubuntu there were no problems, and on Windows 7 it is a scribble - Error

4 answers 4

We take a one-liner.

 perl -alne 'push @{$h{sprintf "%.2f",($F[2]+$F[3]+$F[4])/3.0}}, "$F[0] $F[1]"; END{ print join "\n", map { join ", ", @{ $h{$_} } } grep {if ($c < 3){$c+=$#{$h{$_}}+1}} ( sort { $a <=> $b } keys %h )[0..2] }' 

Parameters decrypt (see perlrun)

 #!/usr/bin/perl while(<>) { chomp; @F = split; push @{$h{sprintf "%.2f",($F[2]+$F[3]+$F[4])/3.0}}, "$F[0] $F[1]"; } print join "\n", map { join ", ", @{ $h{$_} } } grep {if ($c < 3){$c+=$#{$h{$_}}+1}} ( sort { $a <=> $b } keys %h )[0..2]; 

Now we look

  `sprintf "%.2f",($F[2]+$F[3]+$F[4])/3.0` -- средний балл с точностью два знака после запятой (см. perlfunc). push @{$h{sprintf "%.2f",($F[2]+$F[3]+$F[4])/3.0}}, "$F[0] $F[1]"; 

Here, as the hash value of% h for the key "cf. point" we have an array (list), to which we add the surname first name ( "$F[0] $F[1]" ). As a result of the cycle, we have a hash, where the keys are average points, and the values ​​are lists of students who have this point. We get something like

 { 3.00 => ("Троечников Вася", "Троечников Витя", "Троечников Петя") 3.33 => ("Получше Вася", "Получше Петя") } 

The loop has ended (END in a one-liner, awk inheritance), analyze further:

 sort { $a <=> $b } keys %h ) 

Clear - sorting the array of keys - average scores ascending. sort { $a <=> $b } keys %h )[0..2] - array slice (see perldata) - the first three elements of this array.

 grep {if ($c < 3){$c+=$#{$h{$_}}+1}} (...) 

Filtration. $ c, more precisely $ main :: c - the counter of victims or body counter (global variable). Initially not initialized, but on the drum (no -w). Uninitialized means 0. $#{$h{$_}} is the index of the last element of the array, which is the value of $h{$_} (About $_ in perlvar, about $# in perldata). The increase after comparison - it is clear why - the group, where 3 is reached, must enter. If $main::c greater than or equal to 3, then the result of the entire if expression is "impudent lie". (and nonzero values ​​of $ main :: c, which are given out differently, are interpreted as "holy truth"). As a result, we skip the groups, without which the bad guys are less than three. At the exit, we have a filtered array of average points.

 map { join ", ", @{ $h{$_} } } (...) 

Let's transform what happened. $_ accepts sequentially the values ​​of the array-argument, like grep. Argument - filtered avg. points join ", ", @{$h{$_}} - from each list of losers it makes a string, combining the values ​​with ",". As a result of map, we get the lines where the students scored the same score. About the print join "\n", I will keep silent, if someone guesses - I am not guilty

I hope I did not lie much.

  • Cool written. - avp
  • Thank. I did my best. - alexlz
  • Thank. Informative. But pearl is for special brains)) And I am sure that such a decision on pearl is not a task for the unified state examination. In principle, the algorithm is clear and a person familiar with at least one language is able to implement it in the allotted time. But one thing is a program in BASIC (ON BASIC ALL IS POSSIBLE!) To rewrite perl in syntax (operator to operator), another thing is to write "like perler", "like pythonista", "like fortran'tor" ... - Yura Ivanov
  • You can do anything in BASIC, but it reminds a joke: “I can dig, I can stop digging - Can I get a ladder? - I can, but I can dig for a long time”. So from the pearls / BASIC, as I believe, we must stay away. - alexlz
 perl -alne 'push @{$h{sprintf "%.2f",($F[2]+$F[3]+$F[4])/3.0}}, "$F[0] $F[1]"; END{ print join "\n", map { join ", ", @{ $h{$_} } } ( sort { $a <=> $b } keys %h )[0..2] }' 
  • Powerful language perl! And people who know it , apparently suggest that such a program is obviously obvious. - avp
  • there is a suspicion that a program written on a pearl in a different style will be recognized as not satisfying the “as efficient as possible” condition. tin. Threat as far as I can tell, for completing the masterpiece, there is not enough data entry and output for the rest of the people with equally low average points, who are not included in the top three. Although about the second not sure. - Yura Ivanov
  • 2
    Actually, I meant that in response to the forum, it would be nice as an educational program to somehow (preferably with a training bias) comment such beauty. - avp 9:59 pm
  • agree ... - Yura Ivanov
  • one
    In the previous does not fit. Maybe so? perl -alne 'push @ {$ h {sprintf "% .2f", ($ F [2] + $ F [3] + $ F [4]) / 3.0}}, "$ F [0] $ F [ one]"; END {print join "\ n", map {join ",", @ {$ h {$ _}}} grep {if ($ i <3 && $ c <3) {$ i ++; $ c + = $ # {$ h {$ _}} + 1}} (sort {$ a <=> $ b} keys% h) [0..2]} ' - alexlz

The decision, of course, is crooked, do not judge me strictly. If you come up with a better algorithm, I'll rewrite it. )))

 #!/usr/bin/perl print "Content-type: text/html\n\n"; $_ = "Иванов Петр 4 5 3 Сидоров Иван 2 4 5 Петров Павел 4 5 5 Адлор Дло 3 3 3 Лолщдшго Гшортт 3 3 3"; my @ar = split "\n", $_; my %H; foreach ( @ar ) { m/([à-ÿÀ-ß]+?)\s([à-ÿÀ-ß]+?)\s(\d)\s(\d)\s(\d)/; $H{GPA($3, $4, $5)} .= ' ' if $H{GPA($3, $4, $5)}; $H{GPA($3, $4, $5)} .= ($1 . ' ' . $2); } @ar = keys %H; my $min = min( @ar ); my $a1 = $H{$min}; delete $H{$min}; for (my $i=0;$i< @ar ;$i++) { splice( @ar ,$i,1) if $ar[$i]==$min } $min = min( @ar ); my $a2 = $H{$min}; delete $H{$min}; for (my $i=0;$i< @ar ;$i++) { splice( @ar ,$i,1) if $ar[$i]==$min } $min = min( @ar ); my $a3 = $H{$min}; delete $H{$min}; for (my $i=0;$i< @ar ;$i++) { splice( @ar ,$i,1) if $ar[$i]==$min } print "<html><h1>$a1<br>$a2<br>$a3</h1></html>\n"; sub GPA { my $sum = 0; foreach ( @_ ){ $sum += $_; } return $sum/scalar @_ ; } sub min { my $min = $_[0]; foreach ( @_ ) {$min = $_ if $_ < $min} return $min; } 
  • In the sense of ? I did not understand you :) - Error
  • We drove, I corrected the post. - 2Roman

Working with hash arrays on Perl is pretty well described here . It seems to be true. Try it)

Since the list (data file) you have is not sorted (since the opposite is not said), it’s difficult to come up with a beautiful and quick solution ...

  • If for each student one line, then the orderliness of the file does not matter. In the program it is necessary to maintain an array (at the beginning it is empty) of 3 elements for the 3 worst at the moment according to the average score and correct it for each read line. At the end print. Those. sorting (this is about the @ikoolik comment to the question) doesn't need anything at all. But this is only if one line per student. - avp
  • Only elements should also be arrays - those people whose points coincide. This condition, that we need all with the same low scores, even if there are more than three, complicates the algorithm somewhat. - Yura Ivanov
  • I agree. @alexlz and @arto wrote the creation of an array and its sorting by the mean score. Now you just need to learn how to move through the array in a pearl in a loop and print the next line. And as soon as the score has changed and already brought out 3 or more lines, then stop. Or in it (perl) can it be written without an explicit loop? - avp 2:38 pm
  • @avp Well, firstly there is an implicit loop on the input by the -n key. At the map output, a list is formed (in your opinion, an array) containing the string representation for each evaluation, and then by join they are merged into one through the separator \n . Three - set by the key list section (sort ...) [0..2]. Bird has a hash (assoc. Array), where the key is the average score, the value is a list of strings (fam. Name). Then at the end the sorting of the keys of this hash, and processing for the first three. I just added a filter so that the following estimate would not be taken if three victims have already been found. - alexlz
  • 2
    @avp $c+=$#{$h{$_}}+1 in the hash% h - pairs of average score / list of students, respectively $ h {$ _} - this is the list. $ # {$ h {$ _}} is the maximum index in this list. Well, + 1 gives the length of the list (number of pupils with a mean score of $ _ (here the work. Variable is grep). $ C is not assigned, if it participates in the (+) operation, then == 0. (Use of noninits. is forbidden with the -w key. Increases by the number. (wrote what). As for the grep sentences, yes, byak syntax, but also: $ F [0] does not exist at the moment (if it exists, then there is no meaning). autosplit only makes sense in the (-n) input loop. - alexlz