milanHrabos
milanHrabos

Reputation: 1965

Is it possible to push a key-value pair directly to hash in perl?

I know pushing is only passible to array, not hash. But it would be much more convenient to allow pushing key-value pair directly to hash (and I am still surprise it is not possible in perl). I have an example:

#!/usr/bin/perl -w

#superior words begin first, example of that word follow
my @ar = qw[Animals,dog Money,pound Jobs,doctor Food];
my %hash;
my $bool = 1;

sub marine{
    my $ar = shift if $bool;
    for(@$ar){
        my @ar2 = split /,/, $_;
        push %hash, ($ar2[0] => $ar2[1]);
    }
}

marine(\@ar);
print "$_\n" for keys %hash;

Here I have an array, which has 2 words separately by , comma. I would like to make a hash from it, making the first a key, and the second a value (and if it lacks the value, as does the last Food word, then no value at all -> simply undef. How to make it in perl?

Output:

Possible attempt to separate words with commas at ./a line 4.
Experimental push on scalar is now forbidden at ./a line 12, near ");"
Execution of ./a aborted due to compilation errors.

Upvotes: 3

Views: 2799

Answers (3)

amit bhosale
amit bhosale

Reputation: 482

We can assign this array to a hash and perl will automatically look at the values in the array as if they were key-value pairs. The odd elements (first, third, fifth) will become the keys and the even elements (second, fourth, sixth) will become the corresponding values. check url https://perlmaven.com/creating-hash-from-an-array

use strict;
use warnings;
use Data::Dumper qw(Dumper);

my @ar;
my %hash;

#The code in the enclosing block has warnings enabled, 
#but the inner block has disabled (misc and qw) related warnings.
{
    #You specified an odd number of elements to initialize a hash, which is odd, 
    #because hashes come in key/value pairs.
     no warnings 'misc';
     #If your code has use warnings turned on, as it should, then you'll get a warning about 
     #Possible attempt to separate words with commas
     no warnings 'qw';
     @ar = qw[Animals,dog Money,pound Jobs,doctor Food];
     # join the content of array with comma => Animals,dog,Money,pound,Jobs,doctor,Food
     # split the content using comma and assign to hash
     # split function returns the list in list context, or the size of the list in scalar context.
     %hash = split(",", (join(",", @ar)));
}

print Dumper(\%hash);

Output

$VAR1 = {
          'Animals' => 'dog',
          'Money' => 'pound',
          'Jobs' => 'doctor',
          'Food' => undef
        };

Upvotes: 1

Timur Shtatland
Timur Shtatland

Reputation: 12405

Split inside map and assign directly to a hash like so:

my @ar = qw[Animals,dog Money,pound Jobs,doctor Food];
my %hash_new = map { 
                      my @a = split /,/, $_, 2; 
                      @a == 2 ? @a : (@a, undef) 
                   } @ar;

Note that this can also handle the case with more than one comma delimiter (hence splitting into a max of 2 elements). This can also handle the case with no commas, such as Food - in this case, the list with the single element plus the undef is returned.

If you need to push multiple key/value pairs to (another) hash, or merge hashes, you can assign a list of hashes like so:

%hash = (%hash_old, %hash_new);

Note that the same keys in the old hash will be overwritten by the new hash.

Upvotes: 2

GMB
GMB

Reputation: 222622

I might be oversimplyfing things here, but why not simply assign to the hash rather than trying to push into it?

That is, replace this unsupported expression:

push %hash, ($ar2[0] => $ar2[1]);

With:

$hash{$ar2[0]} = $ar2[1];

If I incoporate this in your code, and then dump the resulting hash at the end, I get:

$VAR1 = {
          'Food' => undef,
          'Money' => 'pound',
          'Animals' => 'dog',
          'Jobs' => 'doctor'
        };

Upvotes: 10

Related Questions