I have an list of maps in my code.
my #codeList;
push (#codeList, \%map1, \%map2, \%map3);
when I am trying to access it via looping over List index it is not giving me proper map.
what am I missing.
my $Count = #codeList;
for (my $index =0; $index < $Count; $index++)
{
my %map = $codeList[$index];
}
Instead of
my %map = $dbColsList[$dbCount];
you have to use reference as #codeList was populated with them => \%map1
my $map = $dbColsList[$dbCount];
and later use it like $map->{key} as this is array of hashes or hashref structure.
Check perldoc for details.
Alternatively you can dereference hashref and do a shallow copy (changes to %map keys/values won't reflect on \%map1, etc.)
my %map = %{ $dbColsList[$dbCount] };
Your code works fine. i think its your loop ( which you did'nt show us). You can loop through this by dereferencing the hashref (%{ $hashref }):
use strict;
use warnings;
use feature 'say';
my %map1 = (test1 => 'ab');
my %map2 = (test2 => 'ab');
my %map3 = (test2 => 'ab');
my #codeList;
push (#codeList, \%map1, \%map2, \%map3);
for my $hashref (#codeList) {
for my $key (keys %{$hashref}) {
say $key . q{ } . $hashref->{$key};
}
}
EDIT Output:
test1 ab
test2 ab
test2 ab
Related
How can multiple hash values be retrieved? I tried using
use Hash::MultiValue and get_all(). It throws an error saying "Can't call method "get_all" on an undefined value" . Which is the better option to implement this functionality of multiple values for a particular key ? The value of the key is the file that is being opened.
use warnings;
use List::MoreUtils qw(firstidx);
use Hash::MultiValue;
my $key_in;
…
open ($FR, "<$i") or die "couldn't open list";
while($line=<$FR>){
if($line =~ /search_pattern/){
my $idx = firstidx { $_ eq 'hash_key' } #tags;
my $key= #tags[$idx+1];
$hash{$key}= Hash::MultiValue->new($key=>'$i');
}
close($FR);
for my $key_in ( sort keys %hash ) {
#key_in = $hash->get_all('$key_in');
print "$key_in = $hash{$key_in}\n";
}
my $key_in = <STDIN>;
if (exists($hash{$key_in})){
$hash_value = $hash{$key_in};
}else{
exit;
}
I think you want an array reference for the value. You can then treat that as an array. This is the sort of stuff we show you in Intermediate Perl:
$hash{$key} = [];
push #{ $hash{$key} }, $some_value;
my #values = #{ $hash{$key} };
With Perl v5.24, you can use postfix dereferencing to make it a bit prettier:
use v5.24;
$hash{$key} = [];
push $hash{$key}->#*, 'foo';
push $hash{$key}->#*, 'bar';
my #values = $hash{$key}->#*;
And, since Perl automatically takes an undefined value and turns it into the reference structure you need (auto vivification), you don't need to initialize an undefined value:
use v5.24;
push $hash{$key}->#*, 'foo';
push $hash{$key}->#*, 'bar';
my #values = $hash{$key}->#*;
Get all the keys of a hash:
my #keys = keys %hash;
Get all of the values (in the order of the corresponding keys if you haven't changed the hash since you called keys):
my #values = values %keys;
Get some values with a hash slice:
my #some_values = #hash{#some_keys};
Get some keys and values (key-value slice):
use v5.20;
my %smaller_hash = %hash{#some_keys}
Here is an example of how you can use get_all() from Hash::MultiValue to retrive multiple hash values for a given key:
use strict;
use warnings;
use Data::Dumper qw(Dumper);
use Hash::MultiValue;
my $hash = Hash::MultiValue->new();
$hash->add(tag1 => 'file1');
$hash->add(tag1 => 'file2');
$hash->add(tag2 => 'file3');
my #foo = $hash->get_all('tag1');
print(Dumper(\#foo));
Output:
$VAR1 = [
'file1',
'file2'
];
I want to dump the values of my object and hash, but it keeps printing the keys out of order. How can I dump the keys in (recursive) sort-order?
use Data::Dumper;
print Dumper $obj;
Set $Data::Dumper::Sortkeys = 1 to get Perl's default sort order.
If you want to customize the order, set $Data::Dumper::Sortkeys to a reference to a subroutine that receives a reference to a hash as input, and outputs a reference to the list of the hash's keys in the order you want them to appear.
# sort keys
$Data::Dumper::Sortkeys = 1;
print Dumper($obj);
# sort keys in reverse order - use either one
$Data::Dumper::Sortkeys = sub { [reverse sort keys %{$_[0]}] };
$Data::Dumper::Sortkeys = sub { [sort {$b cmp $a} keys %{$_[0]}] };
print Dumper($obj);
Short answer for the impatient
Use Data::Dumper::Concise instead. It sorts your keys. Use it like this:
use Data::Dumper::Concise;
my $pantsToWear = {
pony => 'jeans',
unicorn => 'corduroy',
marsupials => {kangaroo => 'overalls', koala => 'shorts + suspenders'},
};
warn Dumper($pantsToWear);
More words for the curious
Data::Dumper::Concise also gives you more compact, easier to read output.
Note that Data::Dumper::Concise is Data::Dumper with reasonable default configuration values set for you. Its equivalent to using Data::Dumper like this:
use Data::Dumper;
{
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Useqq = 1;
local $Data::Dumper::Deparse = 1;
local $Data::Dumper::Quotekeys = 0;
local $Data::Dumper::Sortkeys = 1;
warn Dumper($var);
}
You can set the $Data::Dumper::Sortkeys variable to a true value to get a default sort:
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
my $hashref = {
bob => 'weir',
jerry =>, 'garcia',
nested => {one => 'two', three => 'four'}};
print Dumper($hashref), "\n";
or put a subroutine in there to sort the keys however you want.
From the Data::Dumper documentation:
$Data::Dumper::Sortkeys or $OBJ->Sortkeys([NEWVAL])
Can be set to a boolean value to control whether hash keys are dumped in sorted order.
A true value will cause the keys of all hashes to be dumped in Perl's default sort order.
Can also be set to a subroutine reference which will be called for each hash that is dumped.
In this case Data::Dumper will call the subroutine once for each hash, passing it the
reference of the hash. The purpose of the subroutine is to return a reference to an array of
the keys that will be dumped, in the order that they should be dumped. Using this feature, you
can control both the order of the keys, and which keys are actually used. In other words, this
subroutine acts as a filter by which you can exclude certain keys from being dumped. Default is
0, which means that hash keys are not sorted.
For those who want to sort a hashref by value when printing it with Data::Dumper, here is an example:
$Data::Dumper::Sortkeys = sub {
# Using <=> to sort numeric values
[ sort { $_[0]->{$a} <=> $_[0]->{$b} } keys %{ $_[0] } ]
};
And here is a more readable alternative, doing the same but with a variable to hold the hash. It's less efficient, but for small hashes, some may find it nicer:
$Data::Dumper::Sortkeys = sub {
my %h = %{$_[0]};
# cmp for string comparisons
[ sort { $h{$a} cmp $h{$b} } keys %h ];
};
sort ascii and full numeric:
$Data::Dumper::Sortkeys = sub {
no warnings 'numeric';
if(join('',keys %{$_[0]})=~/\d+/)
{
[ sort { $a <=> $b } keys %{$_[0]} ]
}
else
{
return [sort(keys %{$_[0]})];
}
};
$VAR1 = [
'830974',
'722065',
'722046',
'716963'
];
How can I calculate the array index for the value "722065"?
The firstidx function from List::MoreUtils can help:
use strict;
use warnings;
use List::MoreUtils qw(firstidx);
my #nums = ( '830974', '722065', '722046', '716963' );
printf "item with index %i in list is 722065\n", firstidx { $_ eq '722065' } #nums;
__END__
item with index 1 in list is 722065
using List::Util, which is a core module, unlike List::MoreUtils, which is not:
use List::Util qw(first);
my #nums = ( '830974', '722065', '722046', '716963' );
my $index = first { $nums[$_] eq '722065' } 0..$#nums;
Here is how you would find all the positions at which a given value appears:
#!/usr/bin/perl
use strict;
use warnings;
my #x = ( 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1 );
my #i = grep { $x[$_] == 3 } 0 .. $#x;
print "#i\n";
If you only need the first index, you should use List::MoreUtils::first_index.
If you only need to look up the one item, use firstidx as others have said.
If you need to do many lookups, build an index.
If your array items are unique, building an index is quite simple. But it's not much more difficult to build one that handles duplicate items. Examples of both follow:
use strict;
use warnings;
use Data::Dumper;
# Index an array with unique elements.
my #var_uniq = qw( 830974 722065 722046 716963 );
my %index_uniq = map { $var_uniq[$_] => $_ } 0..$#var_uniq;
# You could use hash slice assinment instead of map:
# my %index_uniq;
# #index_uniq{ #var_uniq } = 0..$#var_uniq
my $uniq_index_of_722065 = $index_uniq{722065};
print "Uniq 72665 at: $uniq_index_of_722065\n";
print Dumper \%index_uniq;
# Index an array with repeated elements.
my #var_dupes = qw( 830974 722065 830974 830974 722046 716963 722065 );
my %index_dupes;
for( 0..$#var_dupes ) {
my $item = $var_dupes[$_];
# have item in index?
if( $index_dupes{$item} ) {
# Add to array of indexes
push #{$index_dupes{$item}}, $_;
}
else {
# Add array ref with index to hash.
$index_dupes{$item} = [$_];
}
}
# Dereference array ref for assignment:
my #dupe_indexes_of_722065 = #{ $index_dupes{722065} };
print "Dupes 722065 at: #dupe_indexes_of_722065\n";
print Dumper \%index_dupes;
Here's hastily written attempt at a reverse look-up using a hash.
my $VAR1 = [ '830974', '722065', '722046', '716963' ];
my %reverse;
$reverse{$VAR1->[$_]} = $_ for 0 .. #$VAR1 - 1;
print $reverse{722065};
This does not account for arrays with duplicate values. I do not endorse this solution for production code.
check out the Perl FAQ
use strict;
use Data::Dumper;
sub invert
{
my $i=0;
map { $i++ => $_ } #_;
}
my #a = ('a','b','c','d','e');
print Dumper #a;
print Dumper invert #a;
I am writing a Perl script to do some mathematical operations on a hash. This hash contains the values as given in the sample below. I have written the code below. If I execute this code for an array value separately without using a foreach loop, the output is fine. But if I run this using a foreach loop on the array values, the sum for values in A are good, but from B the output add the previous values.
Hash Sample:
$VAR1 = 'A';
$VAR2 = {
'"x"' => [values],
'"y"' => [values],
and so on...
$VAR3 = 'B';
$VAR4 = {
'"x"' => [values],
'"y"' => [values],
and so on...
$VARn....
Code:
#!/usr/bin/perl -w
use strict;
use List::Util qw(sum);
my #data;
my #count;
my $total;
my #array = ("A", "B", "C", "D");
foreach my $v (#array) {
my %table = getV($v); #getV is a subroutine returing a hash.
for my $h (sort keys %table) {
for my $et (sort keys %{ $table{$h} } ) {
for $ec ($table{$h}{$et}) {
push #data, $ec;
#count = map { sum(#{$_}) } #data;
$total = sum(#count);
}
}
print "sum of $v is $total\n";
}
I think the issue is with this line. It is storing all the previous values and hence adding all the values in next foreach loop.
push #data, $ec;
So, here I have two issues:
1) How can I refresh the array (#data) in each foreach loop iteration?
2) How can I add the values in the array ref ($ec) and store them in an array? Because when I use the following code:
for $ec ($table{$h}{$et}) {
#count = map { sum(#{$_}) } #$ec;
$total = sum(#count);
}
The output gives me the same values for #count and $total.
Please provide me with suggestions.
If I understand you correctly, just a small change in your code. Make an empty array (#data) at the beginning of for loop. Hope this helps.
for my $h (sort keys %table) {
my #data;
1) Declare the #data array at the top of the loop body where you want to start with a fresh, empty array. Or maybe you mean to be saying #data = #$ec, not push #data, $ec?
2) To add the values in the array referred to by $ec, you would just say sum(#$ec); no map required.
It's not completely clear what your data structure is or what you are trying to do with it.
It would help to see what a sample %table looks like and what results you expect from it.
I have an array of HTML::Elements obtained from HTML::TreeBuilder and HTML::Element->find and I need to assign their as_text value to some other variables. I know I can really easily do
my ($var1, $var2) = ($arr[0]->as_text, $arr[1]->as_text);
but I was hoping I could use map instead just to make the code a bit more readable as there are at least 8 elements in the array. I'm really new to Perl so I'm not quite sure what to do.
Can anyone point me in the right direction?
If you're well versed in perldoc -f map it's pretty clear:
my #as_texts = map { $_->as_text } #arr;
Works as well if you want to assign to a list of scalars:
my($var1, $var2, $var3, ...) = map { $_->as_text } #arr;
But of course the array version is better for an unknown number of elements.
Note that, if you just want to map the first two elements of #arr:
my($var1, $var2) = map { $_->as_text } #arr;
will invoke $_->as_text for all elements of #arr. In that case, use an array slice to avoid unnecessary calls:
my($var1, $var2) = map { $_->as_text } #arr[0 .. 1];
Example:
#!/usr/bin/perl
use strict;
use warnings;
my #arr = 'a' .. 'z';
my $count;
my ($x, $y) = map { $count++; ord } #arr;
print "$x\t$y\t$count\n";
$count = 0;
($x, $y) = map { $count++; uc } #arr[0 .. 1];
print "$x\t$y\t$count\n";
Output:
C:\Temp> jk
97 98 26
A B 2
ord was called for each element of #arr whereas uc was called for only the elements we were interested in.