Reputation: 475
In this code two keys "39" are same name but different values , I want to print both keys
use strict;
use warnings;
my %studentnames = (
14 => Martha,
27 =>Vivek,
31 =>Era,
16 =>Marty,
25 =>Jason,
29 =>Socrates,
19 =>Uri,
39 =>Nitin ,
39 =>Plato,
);
foreach my $name (sort keys %studentnames)
{
printf "%-8s %s\n", $name, $studentnames{$name};
}
I am getting error.
Bareword "Martha" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Vivek" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Era" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Marty" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Jason" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Socrates" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Uri" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Nitin" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Plato" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Expected Output
14 Martha
27 Vivek
31 Era
16 Marty
25 Jason
29 Socrates
19 Uri
39 Nitin
39 Plato
Can anyone tell me how to do it?
Upvotes: 9
Views: 190
Reputation: 12405
In addition to excellent answers provided by others, and explanations of how to make the code work (e.g., quote the names, etc), here is another simple solution. I assume that the student names are unique (as they indeed appear in your example). In this case, use the reverse of your hash. That is, change it from the mapping of number to name to the mapping of name to number. Sort the hash by values (student numbers) numerically, then by keys (student names) ASCIIbetically. This is my guess as to one possible way of sorting that makes intuitive sense to the user.
#!/usr/bin/env perl
use strict;
use warnings;
my %student_name_to_num =
reverse (
14 => 'Martha',
27 => 'Vivek',
31 => 'Era',
16 => 'Marty',
25 => 'Jason',
29 => 'Socrates',
19 => 'Uri',
39 => 'Nitin',
39 => 'Plato',
);
foreach my $name ( sort {
$student_name_to_num{$a} <=> $student_name_to_num{$b} ||
$a cmp $b
} keys %student_name_to_num ) {
printf "%-8s %s\n", $student_name_to_num{$name}, $name;
}
Output:
14 Martha
16 Marty
19 Uri
25 Jason
27 Vivek
29 Socrates
31 Era
39 Nitin
39 Plato
Note that the order of the records is different from the sorted order you showed. But it is not clear how you want the records to be sorted (see also my comment under the question).
Upvotes: 2
Reputation: 13664
This is kinda close:
use strict;
use warnings;
use Tie::Hash::MultiValueOrdered;
tie my %studentnames, 'Tie::Hash::MultiValueOrdered';
%studentnames = (
14 => 'Martha',
27 => 'Vivek',
31 => 'Era',
16 => 'Marty',
25 => 'Jason',
29 => 'Socrates',
19 => 'Uri',
39 => 'Nitin',
39 => 'Plato',
);
tied(%studentnames)->fetch_list;
while ( my ( $key, $value ) = each %studentnames ) {
print "$key => @$value\n";
}
But really you want to use a different data structure. Perhaps an array of arrayrefs?
use strict;
use warnings;
my @students = (
[ 14 => 'Martha' ],
[ 27 => 'Vivek' ],
[ 31 => 'Era' ],
[ 16 => 'Marty' ],
[ 25 => 'Jason' ],
[ 29 => 'Socrates' ],
[ 19 => 'Uri' ],
[ 39 => 'Nitin' ],
[ 39 => 'Plato' ],
);
for my $student ( @students ) {
my ( $num, $name ) = @$student;
print "$num => $name\n";
}
Or an array of hashrefs:
use strict;
use warnings;
my @students = (
{ num => 14 , name => 'Martha' },
{ num => 27 , name => 'Vivek' },
{ num => 31 , name => 'Era' },
{ num => 16 , name => 'Marty' },
{ num => 25 , name => 'Jason' },
{ num => 29 , name => 'Socrates' },
{ num => 19 , name => 'Uri' },
{ num => 39 , name => 'Nitin' },
{ num => 39 , name => 'Plato' },
);
for my $student ( @students ) {
print "$student->{num} => $student->{name}\n";
}
Or a hash of arrayrefs:
use strict;
use warnings;
my %students = (
14 => [ 'Martha' ],
27 => [ 'Vivek' ],
31 => [ 'Era' ],
16 => [ 'Marty' ],
25 => [ 'Jason' ],
29 => [ 'Socrates' ],
19 => [ 'Uri' ],
39 => [ 'Nitin', 'Plato' ],
);
for my $key ( sort keys %students ) {
for my $name ( @{$students{$key}} ) {
print "$key => $name\n";
}
}
Or you could even create a lightweight "person" class.
use Z;
my $Person = class sub {
has num => ( type => PositiveInt );
has name => ( type => NonEmptyStr );
};
my @students = (
$Person->new( num => 14, name => 'Marta' ),
$Person->new( num => 27, name => 'Vivek' ),
$Person->new( num => 31, name => 'Era' ),
$Person->new( num => 16, name => 'Marty' ),
$Person->new( num => 25, name => 'Jason' ),
$Person->new( num => 29, name => 'Socrates' ),
$Person->new( num => 19, name => 'Uri' ),
$Person->new( num => 39, name => 'Nitin' ),
$Person->new( num => 39, name => 'Plato' ),
);
for my $student ( @students ) {
printf "%s => %s\n", $student->num, $student->name;
}
There's a lot of ways to go about solving this, but a single flat hash of strings is probably not one of them.
Upvotes: 6
Reputation: 222622
As a starter: the hash values are strings, so they need to be quoted. This is why you are getting a syntax error:
my %studentnames = (
14 => 'Martha',
27 => 'Vivek',
31 => 'Era',
...
);
Then: there is a misconception of what a Perl hash is. Each key in the hash must be unique. Perl tolerates declaring a hash with duplicate keys, but under the hood, only the last value of each key is retained.
So this:
my %studentnames = (
14 => 'Martha',
39 => 'Nitin',
39 => 'Plato'
);
Is equivalent to:
my %studentnames = (
14 => 'Martha',
39 => 'Plato'
);
Another way to see it is to put the assignments in separate instructions:
my %studentnames;
$studentnames{14} = 'Martha';
$studentnames{39} = 'Nitin';
$studentnames{39} = 'Plato';
print $studentnames{39}, "\n";
# Plato
Upvotes: 4
Reputation: 944175
Two keys cannot be the same. One will overwrite the other. If you want to have multiple values for one key then you need to design your data structure to support that (e.g. by having the value be an arrayref).
Your error messages are unrelated to that problem (you forgot to put quotes around your string values).
Upvotes: 9