Can anyone explain how to print all keys if two keys are same but with different values?

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).


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.


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

Tags:

String

Hash

Perl