How to parse multidimensional hash variable in Perl - perl

I have the following multidimensional hash variable
my %billingMember ;
$billingMember{1}->{'useremail_quota'} = 10;
$billingMember{1}->{'useremail_blockedquota'} = 5;
$billingMember{2}->{'useremail_quota'} = 10;
$billingMember{2}->{'useremail_blockedquota'} = 5;
How can i parse the variable %billingMember ?
ie I need to get each value like
$billingMember{1}->{'useremail_quota'},
$billingMember{1}->{'useremail_blockedquota'} ,
$billingMember{2}->{'useremail_quota'}, ....
Here 1& 2 is just for example, it will dynamic
So i think, we need to use foreach or for

Some samples taken from http://perldoc.perl.org/perldsc.html#HASHES-OF-HASHES :
foreach $family ( keys %HoH ) {
print "$family: { ";
for $role ( keys %{ $HoH{$family} } ) {
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}
(Edit : only kept the one which will probably be useful in your case)

Related

particular key value from a hash

I am interested only to know the value of key "DelayedAutoStart" and expect this code to work, but it print much more information. Can someone tell me what is wrong here?
use Win32::Registry;
use Data::Dumper;
$p = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
$p = "SYSTEM\\CurrentControlSet\\Services\\sppsvc";
$main::HKEY_LOCAL_MACHINE->Open($p, $CurrVer) ||
die "Open: $!";
$CurrVer->GetValues(\%vals);
#print Dumper(\%vals);
foreach $k (keys %vals) {
$key = $vals{$k};
if ($$key[0] == "DelayedAutoStart")
{
print "$$key[0] = $$key[2]\n";
}
}
RESULT:
ServiceSidType = 1
ErrorControl = 1
LaunchProtected = 1
DisplayName = #%SystemRoot%\system32\sppsvc.exe,-101
Start = 2
ImagePath = %SystemRoot%\system32\sppsvc.exe
Description = #%SystemRoot%\system32\sppsvc.exe,-100
DelayedAutoStart = 1
ObjectName = NT AUTHORITY\NetworkService
RequiredPrivileges = SeAuditPrivilege SeChangeNotifyPrivilege
SeCreateGlobalPrivilege SeImpersonatePrivilege
FailureActions = ÇQ☺ ♥ ¶ ☺ └È☺ ☺ Óô♦︎
DependOnService = RpcSs
Type = 16
Please add use strict and use warnings to your code. They will give you an error telling you that you're using the wrong kind of comparison operator. The == equality operator is for comparing numbers not strings. You need eq which does a string comparison.
Also, you're confusing matters rather by storing a hash value in a variable called $key and generally making things far more complicated than they need to be!
foreach my $key (keys %vals) {
if ($key eq "DelayedAutoStart")
{
print "$key = $vals{$key}[2]\n";
}
}
But, of course, you can just look up the value in the hash directly. No need to iterate over the keys. That's pretty much the point of using a hash :-)
my $key = 'DelayedAutoStart';
if (exists $vals{$key}) {
print "$vals{$key} = $vals{$key}[2]\n";
}

what does "$K2ko{$D}{$C} = 1" do in perl?

cat inputfile
A<b>Metabolism</b>
B
B <b>Overview</b>
C 01200 Carbon metabolism [PATH:ko01200]
D K00844 HK; hexokinase [EC:2.7.1.1]
D K12407 GCK; glucokinase [EC:2.7.1.2]
...
#
open KO,'<',"inputfile" or die $!;
my ($A,$B,$C,$D,$path_DESC,$KO_DESC);
my %K2ko; my %K2DESC; my %ko2desc;
while (<KO>) {
if (/^A<b>(.+)<\/b>/) {$A=$1;}
elsif (/^B\s+<b>(.+)<\/b>/) {$B=$1;}
elsif (/^C\s+\d+\s+(.+)\s+\[PATH:(ko\d+)\]/) {
$path_DESC=$1;
$C=$2;
$ko2desc{$C} = "$A\t$B\t$path_DESC";
}
elsif (/^D\s+(K\d+)\s+(.*)/) {
$D=$1;
$KO_DESC=$2;
$K2ko{$D}{$C} = 1;
$K2DESC{$D} = $KO_DESC;
}
}
close KO;
#
Could anyone would like to tell me what does "$K2ko{$D}{$C} = 1" do in the perl script?
Thank you for any advice.
This is called a hash of hashes, which gives you a multidimensional hash. Here, "1" is the value for the above mentioned hash key.
Try to use Data::Dumper for know the structure of your data.
use Data::Dumper;
my %K2ko;
my $D = "val1";
my $C = "val2";
$K2ko{$D}{$C} = 1;
print Dumper \%K2ko;
Output
$VAR1 = {
'val1' => {
'val2' => 1
}
};
Using your sample data:
if (/^A<b>(.+)<\/b>/) {$A=$1;}
sets $A to 'Metabolism'
elsif (/^B\s+<b>(.+)<\/b>/) {$B=$1;}
sets $B to 'Overview'
elsif (/^C\s+\d+\s+(.+)\s+\[PATH:(ko\d+)\]/) {...}
sets $path_DESC to 'Carbon metabolism', $C to 'ko01200' and the hash
$ko2desc{'ko01200'} = "Metabolism\tOverview\tCarbon metabolism"
and finally
elsif (/^D\s+(K\d+)\s+(.*)/) {...}
will set
$D='K12407';
$KO_DESC='GCK; glucokinase [EC:2.7.1.2]';
$K2ko{'K12407'}{'ko01200'} = 1;
$K2DESC{'K12407'} = 'GCK; glucokinase [EC:2.7.1.2]';
$K2ko is an hash of hashes, setting it to 1 you can easily see where the component K12407 is used:
print join ',', keys %{$K2ko{'K12407'}};

compare 2 arrays for intersect diff and commmon values

I want to compare 2 arrays and want diff , common and intersect values but below code is not working.
No error message all I can see Array as an value although I am calling $difference[0] so I doubt if the code is correct.
sub updatedevice() {
my $n = {};
my $Device_LINK = $server->object("ICF_PersistentDataSet",$devicelinks);
my $Temp_Device_LINK = $server->object("ICF_PersistentDataSet",$tempdevicelinks);
my #current_devicelist = #{ $Device_LINK->invoke("get") };
my #temp_devicelist = #{ $Temp_Device_LINK->invoke("get") };
my %temp_list;
my %current_list;
my $size = #current_devicelist;
for ($n=0; $n < $size; $n++) {
our $device=$current_devicelist[$n][0];
DEBUG( "DEBUG: - devicelinks values $device " ); --- > able to print this value of device "ABC-DCFE41->90"
my $size = #temp_devicelist;
for ($n=0; $n < $size; $n++) {
our $tempdevicelinks=$temp_devicelist[$n][0];
DEBUG( "DEBUG: - temp plc links values $tempdevicelinks " ); --- > able to print this value of device "GHJKL-poiu->78"
my %count = ();
foreach my $device (#current_devicelist, #temp_devicelist) {
$count{$device}++;
}
my #difference = grep { $count{$_} == 1 } keys %count;
my #intersect = grep { $count{$_} == 2 } keys %count;
my #union = keys %count;
DEBUG( "DEBUG: - difference links values $difference[0] " );
DEBUG( "DEBUG: - intersect links values $intersect[0] " );
DEBUG( "DEBUG: - union links values $union[0] " );
}
}
}
The problem is that you're assigning array reference (returned from invoke to an array).
Your statement of "see 'array' as a value" is a dead giveaway that you're manipulating array references (instead of arrays) - when printed, they turn into strings like this: 'ARRAY(0x349014)'
The problem is that you're taking an array reference (a scalar), and assigning it to an array - which imposes list context on your value, and turns that scalar into a list with its only element being that scalar. Thus you simply store the array reference as the first and only element of the array - instead of storing the list of values that's being referenced like you intended.
To demonstrate:
my #current_devicelist = (1,3); # Assign real arrays
my #temp_devicelist = (2,3);
my %count = ();
foreach my $device (#current_devicelist, #temp_devicelist) {
$count{$device}++;
}
my #difference = grep { $count{$_} == 1 } keys %count;
my #intersect = grep { $count{$_} == 2 } keys %count;
my #union = keys %count;
use Data::Dumper;
print Data::Dumper->Dump([\#difference, \#intersect, \#union]
,["difference","intersect","union"]);
This prints:
$difference = [
'1',
'2'
];
$intersect = [
'3'
];
$union = [
'1',
'3',
'2'
];
Now, if you mimique what your code was doing instead by changing the first 2 lines to:
my #current_devicelist = [1,3]; # Assign reference
# Works the same as if you said
# my #current_devicelist = ([1,3]);
# or
# my $current_devicelist[0] = [1,3];
my #temp_devicelist = [2,3];
... you get:
$difference = [
'ARRAY(0x349014)',
'ARRAY(0x349114)'
];
$intersect = [];
$union = [
'ARRAY(0x349014)',
'ARRAY(0x349114)'
];
To fix your problem, you can do one of 4 things:
Simply dereference your returned array references, using #{} dereference:
my #current_devicelist = #{ $Device->invoke("get") };
my #temp_devicelist = #{ $Temp_Device->invoke("get") };
Change invoke() method - if you can - to return an array instead of array reference:
# Old code:
# return $myArrRef;
# New Code:
return #$myArrRef;
Change invoke() method - if you can - to return an array OR an arrayref based on context (using wantarray):
# Old code:
# return $myArrRef;
# New Code:
return wantarray : #$myArrRef : $myArrRef;
Change your code to use array references
my $current_devicelist = $Device->invoke("get");
my $temp_devicelist = $Temp_Device->invoke("get");
my %count = ();
foreach my $device (#$current_devicelist, #$temp_devicelist) {
$count{$device}++;
}

Add a string to the end of hash values

I'm new in perl and have a question concerning the use of hashes. Althought similar questions were posted before none of them was related to my problem.
I have a fasta file with several sequences of different length and want to add a string (N in this case) to the end of each fasta entry until the length of all sequences are the same. At this point I'm being able to read the fasta file and return each sequence as a string (but can also be done as arrays) to the value of an hash. The key elements are the corresponding headers of the fasta file.
My code is the following:
###### calculate the length of each hash value and store the highest value in $max
my $length;
my $max = 0;
my $addN = "N";
foreach $name ( keys %seq ) {
$length = length($seq{$name});
if ($max < $length) {
$max = $length;
} else { next }
print $max,"\n";
while (length ($seq{$name}) < $max) {
$seq{$name} .= $addN;
}
foreach $name (keys %seq) {
print $seq{$name};
print "\n";
}
}
The problem here is that the output of this code is exactly the same as the input, e.g.,
INPUT:
>fasta1
AAAAAAAAA
>fasta2
AA
OUTPUT
>fasta1
AAAAAAAAA
>fasta2
AA
where I wanted an output like this:
>fasta1
AAAAAAAAA
>fasta2
AANNNNNNN
Can you please help me to accomplish this task?
use 5.014;
my %seq = ( fasta1 => 'AAA',
fasta2 => 'AAAAAA',
fasta3 => 'AAAAAAAAA',
);
my $length = length((sort { length($a) < length($b) } values %seq)[0]);
for my $name ( keys %seq ) {
$seq{$name} = $seq{$name} . ('N' x ($length - length($seq{$name})));
}
while (my($name, $val) = each %seq ) {
say "$name: $val";
}
fasta2: AAAAAANNN
fasta3: AAAAAAAAA
fasta1: AAANNNNNN
Your sample code is wrong. However, it sounds like you have a way to populate a map based on a "fasta" file. Assuming this is true, I think the following code solves your problem.
# Populate %seq from fasta file
%seq = (
"fasta1"=> "AAAAAAAAA",
"fasta2" => "AAAA",
"fasta3" => "AA"
);
my $FILL = "N";
my $normalized_length = 0;
# If the normalized length = longest value
while( my ($k,$v) = each %seq) {
my $len = length($v);
$normalized_length = $len if $len > $normalized_length;
}
while( my ($k,$v) = each %seq) {
print $v, $FILL x ($normalized_length - length($v)), "\n";
}
OUTPUT
AAAANNNNN
AANNNNNNN
AAAAAAAAA
If you need to normalize to a fixed length, then just set $normalized_length to that value and skip the first while loop.

Difference of Two Arrays Using Perl

I have two arrays. I need to check and see if the elements of one appear in the other one.
Is there a more efficient way to do it than nested loops? I have a few thousand elements in each and need to run the program frequently.
Another way to do it is to use Array::Utils
use Array::Utils qw(:all);
my #a = qw( a b c d );
my #b = qw( c d e f );
# symmetric difference
my #diff = array_diff(#a, #b);
# intersection
my #isect = intersect(#a, #b);
# unique union
my #unique = unique(#a, #b);
# check if arrays contain same members
if ( !array_diff(#a, #b) ) {
# do something
}
# get items from array #a that are not in array #b
my #minus = array_minus( #a, #b );
perlfaq4 to the rescue:
How do I compute the difference of two arrays? How do I compute the intersection of two arrays?
Use a hash. Here's code to do both and more. It assumes that each element is unique in a given array:
#union = #intersection = #difference = ();
%count = ();
foreach $element (#array1, #array2) { $count{$element}++ }
foreach $element (keys %count) {
push #union, $element;
push #{ $count{$element} > 1 ? \#intersection : \#difference }, $element;
}
If you properly declare your variables, the code looks more like the following:
my %count;
for my $element (#array1, #array2) { $count{$element}++ }
my ( #union, #intersection, #difference );
for my $element (keys %count) {
push #union, $element;
push #{ $count{$element} > 1 ? \#intersection : \#difference }, $element;
}
You need to provide a lot more context. There are more efficient ways of doing that ranging from:
Go outside of Perl and use shell (sort + comm)
map one array into a Perl hash and then loop over the other one checking hash membership. This has linear complexity ("M+N" - basically loop over each array once) as opposed to nested loop which has "M*N" complexity)
Example:
my %second = map {$_=>1} #second;
my #only_in_first = grep { !$second{$_} } #first;
# use a foreach loop with `last` instead of "grep"
# if you only want yes/no answer instead of full list
Use a Perl module that does the last bullet point for you (List::Compare was mentioned in comments)
Do it based on timestamps of when elements were added if the volume is very large and you need to re-compare often. A few thousand elements is not really big enough, but I recently had to diff 100k sized lists.
You can try Arrays::Utils, and it makes it look nice and simple, but it's not doing any powerful magic on the back end. Here's the array_diffs code:
sub array_diff(\#\#) {
my %e = map { $_ => undef } #{$_[1]};
return #{[ ( grep { (exists $e{$_}) ? ( delete $e{$_} ) : ( 1 ) } #{ $_[0] } ), keys %e ] };
}
Since Arrays::Utils isn't a standard module, you need to ask yourself if it's worth the effort to install and maintain this module. Otherwise, it's pretty close to DVK's answer.
There are certain things you must watch out for, and you have to define what you want to do in that particular case. Let's say:
#array1 = qw(1 1 2 2 3 3 4 4 5 5);
#array2 = qw(1 2 3 4 5);
Are these arrays the same? Or, are they different? They have the same values, but there are duplicates in #array1 and not #array2.
What about this?
#array1 = qw( 1 1 2 3 4 5 );
#array2 = qw( 1 1 2 3 4 5 );
I would say that these arrays are the same, but Array::Utils::arrays_diff begs to differ. This is because Array::Utils assumes that there are no duplicate entries.
And, even the Perl FAQ pointed out by mob also says that It assumes that each element is unique in a given array. Is this an assumption you can make?
No matter what, hashes are the answer. It's easy and quick to look up a hash. The problem is what do you want to do with unique values.
Here's a solid solution that assumes duplicates don't matter:
sub array_diff {
my #array1 = #{ shift() };
my #array2 = #{ shift() };
my %array1_hash;
my %array2_hash;
# Create a hash entry for each element in #array1
for my $element ( #array1 ) {
$array1_hash{$element} = #array1;
}
# Same for #array2: This time, use map instead of a loop
map { $array_2{$_} = 1 } #array2;
for my $entry ( #array2 ) {
if ( not $array1_hash{$entry} ) {
return 1; #Entry in #array2 but not #array1: Differ
}
}
if ( keys %array_hash1 != keys %array_hash2 ) {
return 1; #Arrays differ
}
else {
return 0; #Arrays contain the same elements
}
}
If duplicates do matter, you'll need a way to count them. Here's using map not just to create a hash keyed by each element in the array, but also count the duplicates in the array:
my %array1_hash;
my %array2_hash;
map { $array1_hash{$_} += 1 } #array1;
map { $array2_hash{$_} += 2 } #array2;
Now, you can go through each hash and verify that not only do the keys exist, but that their entries match
for my $key ( keys %array1_hash ) {
if ( not exists $array2_hash{$key}
or $array1_hash{$key} != $array2_hash{$key} ) {
return 1; #Arrays differ
}
}
You will only exit the for loop if all of the entries in %array1_hash match their corresponding entries in %array2_hash. Now, you have to show that all of the entries in %array2_hash also match their entries in %array1_hash, and that %array2_hash doesn't have more entries. Fortunately, we can do what we did before:
if ( keys %array2_hash != keys %array1_hash ) {
return 1; #Arrays have a different number of keys: Don't match
}
else {
return; #Arrays have the same keys: They do match
}
You can use this for getting diffrence between two arrays
#!/usr/bin/perl -w
use strict;
my #list1 = (1, 2, 3, 4, 5);
my #list2 = (2, 3, 4);
my %diff;
#diff{ #list1 } = undef;
delete #diff{ #list2 };
You want to compare each element of #x against the element of the same index in #y, right? This will do it.
print "Index: $_ => \#x: $x[$_], \#y: $y[$_]\n"
for grep { $x[$_] != $y[$_] } 0 .. $#x;
...or...
foreach( 0 .. $#x ) {
print "Index: $_ => \#x: $x[$_], \#y: $y[$_]\n" if $x[$_] != $y[$_];
}
Which you choose kind of depends on whether you're more interested in keeping a list of indices to the dissimilar elements, or simply interested in processing the mismatches one by one. The grep version is handy for getting the list of mismatches. (original post)
n + n log n algorithm, if sure that elements are unique in each array (as hash keys)
my %count = ();
foreach my $element (#array1, #array2) {
$count{$element}++;
}
my #difference = grep { $count{$_} == 1 } keys %count;
my #intersect = grep { $count{$_} == 2 } keys %count;
my #union = keys %count;
So if I'm not sure of unity and want to check presence of the elements of array1 inside array2,
my %count = ();
foreach (#array1) {
$count{$_} = 1 ;
};
foreach (#array2) {
$count{$_} = 2 if $count{$_};
};
# N log N
if (grep { $_ == 1 } values %count) {
return 'Some element of array1 does not appears in array2'
} else {
return 'All elements of array1 are in array2'.
}
# N + N log N
my #a = (1,2,3);
my #b=(2,3,1);
print "Equal" if grep { $_ ~~ #b } #a == #b;
Not elegant, but easy to understand:
#!/usr/local/bin/perl
use strict;
my $file1 = shift or die("need file1");
my $file2 = shift or die("need file2");;
my #file1lines = split/\n/,`cat $file1`;
my #file2lines = split/\n/,`cat $file2`;
my %lines;
foreach my $file1line(#file1lines){
$lines{$file1line}+=1;
}
foreach my $file2line(#file2lines){
$lines{$file2line}+=2;
}
while(my($key,$value)=each%lines){
if($value == 1){
print "$key is in only $file1\n";
}elsif($value == 2){
print "$key is in only $file2\n";
}elsif($value == 3){
print "$key is in both $file1 and $file2\n";
}
}
exit;
__END__
Try to use List::Compare. IT has solutions for all the operations that can be performed on arrays.