I have a hash
%value
g=>10
i=>55
k=>4
n=>100
I have an array
#letters = ('k','i','n','g')
please let me know how to sort my hash in the order of keys in the array.
If you want to print hash values in order in which they appear in #letters array then,
print join ",", #value{#letters};
Code:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Tie::IxHash;
my %hash = (
g=>10,
i=>55,
k=>4,
n=>100,
);
my %sorted_hash;
tie %sorted_hash, "Tie::IxHash";
my #array = ('k','i','n','g');
foreach(#array)
{
if(defined($hash{$_}))
{
$sorted_hash{$_} = $hash{$_};
}
}
print Dumper(%sorted_hash);
Prints:
$VAR1 = 'k';
$VAR2 = 4;
$VAR3 = 'i';
$VAR4 = 55;
$VAR5 = 'n';
$VAR6 = 100;
$VAR7 = 'g';
$VAR8 = 10;
Mention, that I used Tie::ixHash module. Otherwise, Perl won't keep array keys sorted.
This Perl module implements Perl hashes that preserve the order in which the hash elements were added
http://metacpan.org/pod/Tie::IxHash
Related
I am having trouble understanding the hash references and changing the hash in place, instead of returning it. I want to write a sub routine which will return a value from hash and also modify the hash. I was facing some issues while coding for it. So, I wrote the following basic code to understand modifying the hash in place.
#!/usr/local/bin/perl
#Check hash and array references
#Author: Sidartha Karna
use warnings;
use strict;
use Data::Dumper;
sub checkHashRef{
my ($hashRef, $arrVal) = #_;
my %hashDeref = %{$hashRef};
$hashDeref{'check'} = 2;
push(#{$arrVal}, 3);
print "There:" ;
print Dumper $hashRef;
print Dumper %hashDeref;
print Dumper $arrVal
}
my %hashVal = ('check', 1);
my #arrVal = (1, 2);
checkHashRef(\%hashVal, \#arrVal);
print "here\n";
print Dumper %hashVal;
print Dumper #arrVal;
The output observed is:
There:$VAR1 = {
'check' => 1
};
$VAR1 = 'check';
$VAR2 = 2;
$VAR1 = [
1,
2,
3
];
here
$VAR1 = 'check';
$VAR2 = 1;
$VAR1 = 1;
$VAR2 = 2;
$VAR3 = 3;
From the output, I inferred that, changes to hashDeref are not modifying the data in the reference. Is my understanding correct? Is there a way to modify the hash variable in place instead of returning it.
This is making a (shallow) copy of %hashVal:
my %hashDeref = %{$hashRef};
The hash-ref $hashRef still points to %hashVal but %hashDeref doesn't, it is just a copy. If you want to modify the passed hash-ref in-place, then work with the passed hash-ref:
sub checkHashRef{
my ($hashRef, $arrVal) = #_;
$hashRef->{'check'} = 2;
#...
That will leave your changes in %hashVal. In the array case, you never make a copy, you just dereference it in-place:
push(#{$arrVal}, 3);
and the change to $arrVal shows up in #arrVal.
I have the following code in Perl. I am very new to the language:
#!/usr/bin/perl
use strict;
use warnings;
my $date = $ARGV[0];
my $symbols = ('A', 'B', 'C');
foreach $symbol (%symbols)
{
my $print = "$symbol";
print "$print";
}
Getting:
Useless use of a constant in void context at (line of %symbols)
and
Global symbol "$symbol requires explicit package name at ..."
and
Global symbol "%symbols" require explicit package. name at ..."
You are using an Hash when an Array is all that is needed.
#!/usr/bin/perl
use strict;
use warnings;
my $date = $ARGV[0];
my #symbols = ('A', 'B', 'C');
foreach my $symbol (#symbols)
{
print $symbol;
}
1) Your $symbols should be #symbols, since it's an array. Later in the foreach, %symbols should be #symbols.
2) The $symbol is not declared. Say foreach my $symbol... instead.
You are declaring $symbols instead of #symbols, so it is putting that in scalar context and setting it to 'C'. Then you try to loop through a hash with the same name, which you never created. Remember, $a (scalar), #a (array) and %a (hash) are all different.
This is what you wanted:
my #symbols = qw/ A B C /; ## the same as ( 'A', 'B', 'C' )
foreach my $symbol ( #symbols ) {
print $symbol;
}
Really quick:
my #symbols = qw/ A B C /; ## new array with three values
my $symbols = qw/ A B C /; ## new scalar that is the last element of the "A B C" list ($symbols = 'C')
my %symbols = (
A => 1,
B => 2,
C => 3,
); ## a hash with three key/value pairs
Your foreach is looking at each symbol in a non-existent hash called %symbols, not your array #symbols.
foreach $symbol (#symbols)
{
my $print = "$symbol";
print "$print";
}
Can anyone make this print "4" by replacing the PFM block??
my %hash;
$hash{1}{2}{3}=4;
my #key=qw(1 2 3);
my $key;
for(#key){PFM}
print $hash{$key}
my %hash;
$hash{1}{2}{3}=4;
my #key=qw(1 2 3);
my $data = \%hash;
for(#key){
$data = $data->{$_}
}
print $data
my $val = \%hash;
$val //= $val->{$_} for #key;
say $val;
or you could use Data::Diver
use Data::Diver qw( Dive );
say Dive(\%hash, #key);
Neither version will vivify anything if any part of the key doesn't exist.
If you want to set a value using such a key:
my $p = \\%hash;
$p = \( $$p->{$_} ) for #key;
$$p = 5;
or
use Data::Diver qw( DiveRef );
my $ref = DiveRef(\%hash, map \$_, #key);
$$ref = 5;
or
use Data::Diver qw( DiveVal );
DiveVal(\%hash, map \$_, #key) = 5;
(The map \$_, is required to make Data::Diver make hashes instead of arrays for numerical keys.)
Yes. But it's probably not what you wanted:
$key = "X";
$hash{X} = 4;
4 is not a value of the %hash originally:
my #fours = grep $_ == 4, values %hash;
print "[#fours]\n"; # prints '[]'
I noticed a hash object was once defined as in the following:
my %data = ();
$data{file} = $file;
$data{concept} = $#row;
$data{line1} {$cell[0]} = $cell[1];
What does this hash construction process try to achieve? Or what is the difference between
$data{concept} = $#row;
and
$data{line1} {$cell[0]} = $cell[1];
?
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $file = "contents of my file";
my #row = qw(some random data);
my #cell = qw(key value);
my %data = ();
$data{file} = $file;
$data{concept} = $#row;
$data{line1} {$cell[0]} = $cell[1];
print Dumper \%data;
Output:
$VAR1 = {
'file' => 'contents of my file',
'line1' => {
'key' => 'value'
},
'concept' => '2'
};
I think $data{line1} {$cell[0]} is better written as $data{line1}{$cell[0]} or (my preference) $data{line1}->{$cell[0]}.
I included the scalar $file and the arrrays #row and #cell to demonstrate what your code means.
$data{file} = $file;
adds the contents of $file to your hash with the key file.
$data{concept} = $#row;
adds the last index of #row to your hash with the key concept. In my example the last index is 2, since the indexes in #row are 0, 1 and 2.
$data{line1} {$cell[0]} = $cell[1];
adds a hash ref to your hash with the key line1 (through autovivification) and adds the element $cell[1] to this hash ref with the key $cell[0]. Autovivification in this case means that Perl associates line1 with a hash ref and creates it, because you're accessing it with {$cell[0]}. That saves you the trouble of having to write:
$data{line} = {};
$data{line}{$cell[0]} = $cell[1];
How can I preserve the order in which the hash elements were added
FOR THE SECOND VAR ?
( Hash of Hashes )
For example:
use Tie::IxHash;
my %hash;
tie %hash, "Tie::IxHash";
for my $num (0 .. 5){
$hash{"FirstVal$num"}++;
}
for my $num (0 .. 5){
$hash{"FirstValFIXED"}{"SecondVal$num"}++;
}
print Dumper(%hash);
When dumping out the result, $VAR14 didn't preserve the insertion order:
$VAR1 = 'FirstVal0';
$VAR2 = 1;
$VAR3 = 'FirstVal1';
$VAR4 = 1;
$VAR5 = 'FirstVal2';
$VAR6 = 1;
$VAR7 = 'FirstVal3';
$VAR8 = 1;
$VAR9 = 'FirstVal4';
$VAR10 = 1;
$VAR11 = 'FirstVal5';
$VAR12 = 1;
$VAR13 = 'FirstValFIXED';
$VAR14 = {
'SecondVal5' => 1,
'SecondVal4' => 1,
'SecondVal2' => 1,
'SecondVal1' => 1,
'SecondVal3' => 1,
'SecondVal0' => 1
};
I know I can trick that example with some sort operation but in my real problem the elements are not numbered or can't be ordered some how.
Is there any simple function/operation for hash multi level order insertion ?
Thanks,
Yodar.
Look at Tie::Autotie. It automatically ties new hashes created by autovivification. The perldoc page shows an example using Tie::IxHash.
You need an extra "\", as below.
print Dumper(\%hash);
Do you mean hash of hashes? You need to tie to Tie::IxHash every value of outer hash.
use strict;
use warnings;
use Tie::IxHash;
my $hash={};
my $t = tie(%$hash, 'Tie::IxHash', 'a' => 1, 'b' => 2);
%$hash = (first => 1, second => 2, third => 3);
$hash->{fourth} = 4;
print join(', ',keys %$hash),"\n";
my %new_hash=('test'=>$hash);
$new_hash{'test'}{fifth} = 5;
print join(', ',keys %{$new_hash{'test'}}),"\n";
$new_hash{'test'}{fifth}++;
print join(', ',values %{$new_hash{'test'}}),"\n";
foreach my $sortline (sort {$a<=>$b} keys %{$hash->{"first_field"}}){
my $name;
# Soultion to touch a Key with keys within it:
#---------------------------------------------
foreach my $subkey (keys %{$hash->{"first_field"}->{$sortline}})
{$name = $subkey;}
#---------------------------------------------
}
This useful answer helped me.