2

I am new to Perl and I'm trying to understand the map function.

my %names = qw (hanibal lecter Harry Potter INDIANA JONES Sarah connor scarlet O’Hara JAMES Bond);
my ($k, $v);
my @names;
while (($k,$v) = each %names) {
    my @name ;
    push(@name , $k);
    push(@name , $v);
    push(@names, \@name);
}
print "Unsorted names : \n";
foreach(0..$#names) {
    print "@{$names[$_]}\n";
} 

This works, and prints all the names like this

hanibal lecter
scarlet O¦Hara
Harry Potter
Sarah connor
INDIANA JONES
JAMES Bond

I have modified a little my code and know it looks like this:

my %names = map { $_ } qw (hanibal lecter Harry Potter INDIANA JONES Sarah connor scarlet O’Hara JAMES Bond);
my ($k, $v);
my @names;
while (($k,$v) = each %names) {
    my @name = map {$k, $v} ($k,$v) ;
    #my @name;
    #push(@name , $k);
    #push(@name , $v);
    push(@names, \@name);
}
foreach(0..$#names) {
    print "@{$names[$_]}\n";
}

The hash is created corectly but the array is not The output is

hanibal lecter hanibal lecter
scarlet O▒Hara scarlet O▒Hara
Harry Potter Harry Potter
Sarah connor Sarah connor
INDIANA JONES INDIANA JONES
JAMES Bond JAMES Bond

Why does it double every record?

4 Answers 4

3

Map produces a new list by iterating through a list and for each element, calling a block of code to produce elements for the new list.

You say:

my @name = map {$k, $v} ($k,$v) ;

which causes the code in {} to be called twice, once for the $k in the parenthesised list and once for the $v. Because you don't use $_ in the code block, the input isn't significant except to determine the number of times the code block is called. You would get the same results from

my @name = map {$k, $v} (1,2) ;

or

my @name = map {$k, $v} ( 'donkey', 'zebra' ) ;

Each time the code block is called, it returns a list with two elements with the values of $k and $v, so map returns a list of four elements with the values of $k,$v,$k,$v.

Sign up to request clarification or add additional context in comments.

3 Comments

So there is no way to create my hash using map?
Of course there is: my @primes = qw/ 2 3 5 7 11 /; my %doubled_primes = map { $_, 2*$_ } @primes;
you could use the same do-nothing map: my @name = map {$_} $k, $v; but here again, just like with the %names assignment, you already have the list you want, so map isn't helpful. why do you want to use map?
0

Your hash should just work for this. If you want to have a better visual representation of what your data is doing is better to use the fat comma to do it. For example:

my %names = ("hanibal" => "lecter",  "Harry" => "Potter", "INDIANA" => "JONES", 
             "Sarah" => "connor", "scarlet" => "OHara", "JAMES" => "Bond");

say "First name is $_ and last name is $names{$_}" for keys %names

Output:

First name is Sarah and last name is connor
First name is JAMES and last name is Bond
First name is hanibal and last name is lecter
First name is INDIANA and last name is JONES
First name is Harry and last name is Potter
First name is scarlet and last name is OHara

If I misunderstood your request, please clarify.

Comments

0

Hashes are just lists of key/value pairs, so when you do

my %names = qw(hanibal lecter Harry Potter INDIANA JONES Sarah connor scarlet O’Hara JAMES Bond);

you already have a full-fledged hash:

%names = (
    hanibal => "lecter",
    Harry   => "Potter",
    INDIANA => "JONES",
    JAMES   => "Bond",
    Sarah   => "connor",
    scarlet => "O’Hara",
);

so if you were to apply a map to this while trying to get the same result, it would have to just be creating a list of all the values you already have (mapping the identity function):

my %hash = map { $_ } qw(...);

which is of course pointless. Use map when you need to transform the elements of a list into a new list. For example, if you wanted to create a hash out of the properly capitalized names, you could do:

my %names = map { ucfirst(lc($_)) } qw(...);

which creates a hash like this:

%names = {
    Hanibal => "Lecter",
    Harry   => "Potter",
    Indiana => "Jones",
    James   => "Bond",
    Sarah   => "Connor",
    Scarlet => "O’hara",
}

Since arrays are just lists of values and hashes are lists of keys => values, they can be used somewhat interchangeably when it comes to list operators. To make an array out of a hash, just do:

my @array = %hash;

You usually won't need to do this, but if you want to do something like print each key/value pair in alphabetical order on its own line, separated by spaces, it's easiest to do something like this:

my @full_names;
while (my ($key, $val) = each %names)
{
    push @full_names, "$key $val"; # Concatenate first and last names so they
}                                  # stick together when sorted
print join "\n", sort @full_names;

Comments

0

I have read a lot of examples for map but none creates a hash from an array how I want to to do it (the first element is the key and the second is the value and so on..).

Map always returns a list, which can be assigned to a hash such that the elements become key/value pairs. See perldata for more details.

my %hash = map {split /,/} @array; 

Demo

is same as

my %hash = @array; 

Demo


Creating an array from hash

my @array = %hash;

Demo

2 Comments

Thanks, tha worked. Do you have any idea how I could build the other array(@names) which stores a reference to each name(key, value). I still want to do it using map
See the edited answer, I wonder why you need to use map when it's not even needed?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.