two dimensional hash data output?

2019-08-16 15:05发布

问题:

this my code.At the end of this process I want to collect name and sum results with ascending order and want to print.I tried to take the as @sum1 and @sum2 but it couldn't know @sum functions.How can I do that or any idea will be very valuable.

#!/usr/bin/perl

use strict;
use warnings;
use List::Util qw( sum );
use Data::Dumper qw(Dumper);

my %grades;
$grades{"Ahmet"}{quiz1}  = 97;
$grades{"Ahmet"}{quiz2}  = 67;
$grades{"Ahmet"}{quiz3}  = 93;
$grades{"Mehmet"}{quiz1} = 88;
$grades{"Mehmet"}{quiz2} = 82;
$grades{"Mehmet"}{quiz3} = 99;

print Dumper \%grades;
print "----------------\n";

foreach my $name ( sort keys %grades ) {
    my %hash1 = (
        'Ahmet'  => [ 97, 67, 93 ],
        'Mehmet' => [ 88, 82, 99 ],
    );

    my @sums;
    for my $key ( keys %hash1 ) {
        my $sum = sum @{ $hash1{$key} };
        push @sums, "$key: $sum\n";
    }

    foreach my $sum ( keys %{ $grades{$name} } ) {
        print "$name : $grades{$name}{$sum}\n";
    }

    print @sums;
}

foreach my $name ( sort keys %grades ) {
    print "$grades{$name}\n";
}

my %grades2;
$grades2{"Merve"}{quiz1} = 33;
$grades2{"Merve"}{quiz2} = 41;
$grades2{"Merve"}{quiz3} = 59;
$grades2{"Aslı"}{quiz1} = 79;
$grades2{"Aslı"}{quiz2} = 31;
$grades2{"Aslı"}{quiz3} = 62;

print Dumper \%grades2;
print "----------------\n";

foreach my $name2 ( sort keys %grades2 ) {
    my %hash = (
        'Merve' => [ 33, 41, 59 ],
        'Aslı' => [ 79, 31, 62 ],
    );

    my @sums2;
    for my $key ( keys %hash ) {
        my $sum = sum @{ $hash{$key} };
        push @sums2, "$key: $sum\n";
    }

    foreach my $sum ( keys %{ $grades2{$name2} } ) {
        print "$name2 : $grades2{$name2}{$sum}\n";
    }

    print @sums2;

}

foreach my $name2 ( sort keys %grades2 ) {
    print "$grades2{$name2}\n";
}

my %info;

$info{$_} .= "A" for keys %grades;
$info{$_} .= "B" for keys %grades2;

for ( sort keys %info ) {
    print "$_ : $info{$_}\n";
}

回答1:

You seem to duplicate some information in your code. Once you populate the %grades, there's no need to create the %hash - it can be extracted from the %grades directly.

To populate the hashes, you don't have to repeat the keys all the time, describe the substructure as shown below.

Also, your code contains "ı", which isn't an ASCII character. It would be nicer to tell Perl that by using utf8 and also declaring the encoding of the output.

To sort the output by sums, use the sort function with a custom block that compares the hash elements:

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use open ':encoding(UTF-8)', ':std';

use List::Util qw( sum );

my %grades = (
    Ahmet => {
        quiz1 => 97,
        quiz2 => 67,
        quiz3 => 93,
    },
    Mehmet => {
        quiz1  => 88,
        quiz2  => 82,
        quiz3  => 99,
    }
);

my %sum;
for my $name (keys %grades)
  {
    $sum{$name} = sum(values %{ $grades{$name} });
}
for my $name (sort { $sum{$a} <=> $sum{$b} } keys %sum)
  {
    print $name, ' ', $sum{$name}, "\n";
  }

my %grades2 = (
    Merve => {
        quiz1 => 33,
        quiz2 => 41,
        quiz3 => 59,
    },
    Aslı => {
        quiz1 => 79,
        quiz2 => 31,
        quiz3 => 62,
    },
);

my %sum2;
for my $name (keys %grades2)
  {
    $sum2{$name} = sum(values %{ $grades2{$name} });
  }
for my $name (sort { $sum2{$a} <=> $sum2{$b} } keys %sum2)
  {
    print $name, ' ', $sum2{$name}, "\n";
  }


回答2:

Here is a way to do it. You are creating a hash of hash ref, which is explicitly done like this (I have added one more student to make the example more interesting):

my %grades = (
  'Ahmet' => {
    quiz1 => 97,
    quiz2 => 67,
    quiz3 => 93,
  },
  'Mehmet' => {
    quiz1 => 88,
    quiz2 => 82,
    quiz3 => 99,
  },
  'Abdul' => {
    quiz1 => 99,
    quiz2 => 89,
    quiz3 => 99,
  },
);

To print the students and their grades, you may use:

# Printing the students and grades
foreach my $student ( keys %grades ) {
  print $student, ":\n";
  foreach my $test ( keys %{$grades{$student}} ) {
    print " - ", $test, "\t", $grades{$student}{$test}, "\n";
  }
}

To generate the sum for each student:

# Generating a sum for each student
my %sums;
foreach my $student ( keys %grades ) {
  $sums{$student} = sum0 map { $grades{$student}{$_} } keys %{$grades{$student}};
}

I use sum0 which will return 0 instead of undef when the list it is given is empty. You should use use List::Util qw( sum0 ); at the beginning.

Then printing the generated sum in ascending order:

# Printing the sum
foreach my $student ( sort { $sums{$a} <=> $sums{$b} } keys %sums ) {
  print $student, ":\t", $sums{$student}, "\n";
}

For the opposite order, you may use sort { $sums{$b} <=> $sums{$a} } keys %sums. For the rest of your code, you would do the same...

The output of the students:

Ahmet:
 - quiz1        97
 - quiz3        93
 - quiz2        67
Mehmet:
 - quiz2        82
 - quiz3        99
 - quiz1        88
Abdul:
 - quiz2        89
 - quiz3        99
 - quiz1        99

Then the sum of the grades:

Ahmet:  257
Mehmet: 269
Abdul:  287