I want to increment the value of hash starting from 0 for each $COMMUNITY, I define an array #indicator from 0 until the same index of the array #NAME and push it to become the value, but it is not I want exactly, and I don't know how to this. I know very well that the value is not in the order because the place in array in not organized first, but how to do this exactly, and then,
how to print every first value of subhash $FAMILY.
for example,
community 0 = name 0 4 7
community 1 = name 0 3 8
community 2 = name 0 3 6
#!/usr/bin/perl
use warnings;
use strict;
use Tie::Autotie 'Tie::IxHash';
my #NAME= qw(AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AD CD CE CF BD BE);
my #FAMILY= qw(A A A B B B C C C A A A B B B C C C A A A B B B C C C A C C C B B);
my #COMMUNITY= qw(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 0 2 2 2 1 1);
tie my %COMMUNITY_FAMILY_NAME,'Tie::IxHash' ;
my #indicator;
foreach (my $x=0;$x<=scalar #NAME;$x++)
{
push #indicator,$x;
}
push #{ $COMMUNITY_FAMILY_NAME{ $COMMUNITY[$_] }{ $FAMILY[$_]}{$NAME[$_]} }, $indicator[$_] for 0 .. $#NAME;
print Dumper(\%COMMUNITY_FAMILY_NAME);
Output:
$VAR1 = {
'0' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
],
'AD' => [
27
]
},
'B' => {
'BA' => [
3
],
'BB' => [
4
],
'BC' => [
5
]
},
'C' => {
'CA' => [
6
],
'CB' => [
7
],
'CC' => [
8
]
}
},
'1' => {
'A' => {
'AA' => [
9
],
'AB' => [
10
],
'AC' => [
11
]
},
'B' => {
'BA' => [
12
],
'BB' => [
13
],
'BC' => [
14
],
'BD' => [
31
],
'BE' => [
32
]
},
'C' => {
'CA' => [
15
],
'CB' => [
16
],
'CC' => [
17
]
}
},
'2' => {
'A' => {
'AA' => [
18
],
'AB' => [
19
],
'AC' => [
20
]
},
'B' => {
'BA' => [
21
],
'BB' => [
22
],
'BC' => [
23
]
},
'C' => {
'CA' => [
24
],
'CB' => [
25
],
'CC' => [
26
],
'CD' => [
28
],
'CE' => [
29
],
'CF' => [
30
]
}
}
};
Expected output:
$VAR1 = {
'0' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
],
'AD' => [
3
]
},
'B' => {
'BA' => [
4
],
'BB' => [
5
],
'BC' => [
6
]
},
'C' => {
'CA' => [
7
],
'CB' => [
8
],
'CC' => [
9
]
}
},
'1' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
]
},
'B' => {
'BA' => [
3
],
'BB' => [
4
],
'BC' => [
5
],
'BD' => [
6
],
'BE' => [
7
]
},
'C' => {
'CA' => [
8
],
'CB' => [
9
],
'CC' => [
10
]
}
},
'2' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
]
},
'B' => {
'BA' => [
3
],
'BB' => [
4
],
'BC' => [
5
]
},
'C' => {
'CA' => [
6
],
'CB' => [
7
],
'CC' => [
8
],
'CD' => [
9
],
'CE' => [
10
],
'CF' => [
11
]
}
}
};
You need to iterate the elements by communities, resetting the counter for each. So, I first created the structure with no counters, and then iterated over it in the correct order while setting the values.
#!/usr/bin/perl
use strict;
use warnings;
use Tie::Autotie 'Tie::IxHash';
my #NAMES = qw(AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AD CD CE CF BD BE);
my #FAMILIES = qw(A A A B B B C C C A A A B B B C C C A A A B B B C C C A C C C B B);
my #COMMUNITIES = qw(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 0 2 2 2 1 1);
tie my %community_family_name, 'Tie::IxHash' ;
undef $community_family_name{ $COMMUNITIES[$_] }{ $FAMILIES[$_]}{$NAMES[$_]}
for 0 .. $#NAMES;
for my $community (keys %community_family_name) {
my $i = 0;
for my $family (keys %{ $community_family_name{$community} }) {
for my $name (keys %{ $community_family_name{$community}{$family} }) {
$community_family_name{$community}{$family}{$name} = [$i++];
}
}
}
use Data::Dumper; print Dumper(\%community_family_name);
Note: Are you sure the values need to be in an array ref? There's never more than one value.
By convention, lowercase names are used for mutable variables in Perl.
Related
I want to print the values of every first $family reversely, and the first value it prints is the total scalar value in each $community.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Tie::Autotie 'Tie::IxHash';
my #NAMES = qw(AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AD CD CE CF BD BE);
my #FAMILIES = qw(A A A B B B C C C A A A B B B C C C A A A B B B C C C A C C C B B);
my #COMMUNITIES = qw(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 0 2 2 2 1 1);
tie my %community_family_name, 'Tie::IxHash' ;
undef $community_family_name{ $COMMUNITIES[$_] }{ $FAMILIES[$_]}{$NAMES[$_]}
for 0 .. $#NAMES;
for my $community (keys %community_family_name) {
my $i = 0;
for my $family (keys %{ $community_family_name{$community} }) {
for my $name (keys %{ $community_family_name{$community}{$family} }) {
$community_family_name{$community}{$family}{$name} = $i++;
}
}
}
foreach my $community (sort keys %community_family_name)
{
foreach my $family (keys %{ $community_family_name{$community} })
{
foreach my $name (keys %{ $community_family_name{$community}{$family}})
{
print "[$community] = ";
print scalar "%{ $community_family_name{$community}";
print reverse "$community_family_name{$community}{$family}{$name}";
print " ";
}
}
}
print Dumper(\%community_family_name);
Current output:
[0] = HASH(0x1038c80)0 [0] = HASH(0x1038c80)1 [0] = HASH(0x1038c80)2 [0] = HASH(0x1038c80)3 [0] = HASH(0x1038c80)4 [0] = HASH(0x1038c80)5 [0] = HASH(0x1038c80)6 ...
Expected output:
[0] = 10 7 4 0
[1] = 11 8 3 0
[2] = 12 6 3 0
What is in the %community_family_name
$VAR1 = {
'0' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
],
'AD' => [
3
]
},
'B' => {
'BA' => [
4
],
'BB' => [
5
],
'BC' => [
6
]
},
'C' => {
'CA' => [
7
],
'CB' => [
8
],
'CC' => [
9
]
}
},
'1' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
]
},
'B' => {
'BA' => [
3
],
'BB' => [
4
],
'BC' => [
5
],
'BD' => [
6
],
'BE' => [
7
]
},
'C' => {
'CA' => [
8
],
'CB' => [
9
],
'CC' => [
10
]
}
},
'2' => {
'A' => {
'AA' => [
0
],
'AB' => [
1
],
'AC' => [
2
]
},
'B' => {
'BA' => [
3
],
'BB' => [
4
],
'BC' => [
5
]
},
'C' => {
'CA' => [
6
],
'CB' => [
7
],
'CC' => [
8
],
'CD' => [
9
],
'CE' => [
10
],
'CF' => [
11
]
}
}
};
You are almost there.
The first point is your expected result is per community, so your print functions must stay in the first loop.
The second is you must use scalar and reverse to arrays, not to scalar value such as double-quoted strings.
# Let me shorten your variable name, that's way too long...
my %cfn = %community_family_name;
foreach my $com (sort keys %cfn) {
# Count up keys in the community
my $count = map { keys %{$cfn{$com}->{$_}} } keys %{$cfn{$com}};
my #vals;
foreach my $family (reverse sort keys %{$cfn{$com}}) {
my ($first) = sort keys %{$cfn{$com}->{$family}};
push #vals, #{$cfn{$com}->{$family}->{$first}};
}
printf "[%d] = %s", $com, join q{ }, $count, #vals;
print "\n";
}
How I can save these Arrays into this Hash Of Arrays in order, not following alphabetically order, just save according to the Arrays.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- stackoverflow won't allow me to post because not enough details, so I did this -
#!/usr/bin/perl
use warnings;
use strict;
use Tie::IxHash;
use Data::Dumper;
my #NAME= qw(AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AA AB AC BA BB BC CA CB CC AD CD CE CF BD BE);
my #FAMILY= qw(A A A B B B C C C A A A B B B C C C A A A B B B C C C A C C C B B);
my #COMMUNITY= qw(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 0 2 2 2 1 1);
tie my %COMMUNITY_FAMILY_NAME,'Tie::IxHash' ;
push #{ $COMMUNITY_FAMILY_NAME{ $COMMUNITY[$_] }{ $FAMILY[$_] } }, $NAME[$_] for 0 .. $#NAME;
print Dumper(\%COMMUNITY_FAMILY_NAME);
Output:
$VAR1 = {
'0' => {
'A' => [
'AA',
'AB',
'AC',
'AD'
],
'C' => [
'CA',
'CB',
'CC'
],
'B' => [
'BA',
'BB',
'BC'
]
},
'1' => {
'A' => [
'AA',
'AB',
'AC'
],
'C' => [
'CA',
'CB',
'CC'
],
'B' => [
'BA',
'BB',
'BC',
'BD',
'BE'
]
},
'2' => {
'A' => [
'AA',
'AB',
'AC'
],
'C' => [
'CA',
'CB',
'CC',
'CD',
'CE',
'CF'
],
'B' => [
'BA',
'BB',
'BC'
]
}
};
Expected Output:
$VAR1 = {
'0' => {
'A' => [
'AA',
'AB',
'AC',
'AD'
],
'B' => [
'BA',
'BB',
'BC'
]
'C' => [
'CA',
'CB',
'CC'
],
},
'1' => {
'A' => [
'AA',
'AB',
'AC'
],
'B' => [
'BA',
'BB',
'BC',
'BD',
'BE'
'C' => [
'CA',
'CB',
'CC'
],
]
},
'2' => {
'A' => [
'AA',
'AB',
'AC'
],
'B' => [
'BA',
'BB',
'BC'
]
'C' => [
'CA',
'CB',
'CC',
'CD',
'CE',
'CF'
],
}
};
Your subhashes are not tied to Tie::IxHash, and thus they are plain/unordered. You can change that by tie every subhash before usage.
# push #{ $COMMUNITY_FAMILY_NAME{ $COMMUNITY[$_] }{ $FAMILY[$_] } }, $NAME[$_] for 0 .. $#NAME;
for (0 .. $#NAME) {
my $href = $COMMUNITY_FAMILY_NAME{ $COMMUNITY[$_] } ||= do {
tie my %hash, 'Tie::IxHash';
\%hash;
};
push #{ $href->{ $FAMILY[$_] } }, $NAME[$_];
}
The issue you're running into is that a tied hash only affects one level - each value of a tied hash is just whatever you store in it, which usually is a normal perl value. That means if you want a multi-dimensional tied hash, both the top level variable has to be tied, and any values stored in it (In this case, hashrefs) as well.
For example:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use Tie::IxHash;
tie my %hash, 'Tie::IxHash';
tie %{$hash{"b"}}, 'Tie::IxHash';
tie %{$hash{"c"}}, 'Tie::IxHash';
$hash{"b"}->{"b"} = [ qw/1 2 3/ ];
$hash{"b"}->{"a"} = [ qw/4 5 6/ ];
$hash{"c"}->{"d"} = [ qw/7 8 9/ ];
$hash{"c"}->{"c"} = [ qw/10 11 12/ ];
print Dumper(\%hash);
I have a Hash of following structure in perl -
my %testHash = (
KeyL1 => {
KeyLL1 => {
KeyLLL1 => [1,2],
KeyLLL2 => [2,3],
},
KeyLL2 => {
KeyLLL1 => [1,2],
KeyLLL2 => [2,3],
},
KeyLL3 => {
KeyLLL1 => [1,2],
KeyLLL2 => [2,3],
},
},
KeyL2 => {
KeyLL1 => {
KeyLLL1 => [1,2],
KeyLLL2 => [2,3],
},
KeyLL2 => {
KeyLLL1 => [1,2],
KeyLLL2 => [2,3],
},
KeyLL3 => {
KeyLLL1 => [1,2],
KeyLLL2 => [2,3],
},
},
);
Now, when I am trying to access it the following way, I am getting 'undef' as a result
my %tempHash = $testHash{'KeyL1'};
print Data::Dumper::Dumper($tempHash{'KeyLL1'});
print Data::Dumper::Dumper($tempHash{'KeyLL1'}{'KeyLLL1'});
Result --
$VAR1 = undef; $VAR1 = undef;
Please point to me what am I doing wrong. I am pretty new to perl.
The value of $testHash{'KeyL1'} is a hashref, not a hash.
Hashrefs are scalars. my %tempHash = is not expecting a scalar.
You need to dereference it:
my %tempHash = %{$testHash{'KeyL1'}};
Also, you could do it this way if its just about viewing the structures.
Also try:
print Dumper $testHash{KeyL1} ;
print Dumper $testHash{KeyL1}{KeyLL1} ;
print Dumper $testHash{KeyL1}{KeyLL1}{KeyLLL1} ;
Output:
%_Host#User> ./hash.pl
$VAR1 = {
'KeyLL1' => {
'KeyLLL2' => [
2,
3
],
'KeyLLL1' => [
1,
2
]
},
'KeyLL2' => {
'KeyLLL2' => [
2,
3
],
'KeyLLL1' => [
1,
2
]
},
'KeyLL3' => {
'KeyLLL2' => [
2,
3
],
'KeyLLL1' => [
1,
2
]
}
};
$VAR1 = {
'KeyLLL2' => [
2,
3
],
'KeyLLL1' => [
1,
2
]
};
$VAR1 = [
1,
2
];
%_Host#User>
I am trying to parse xml using xml::simple .Here is the output of xml::simple
$VAR1 = {
'soapenv:Body'=>[
{
'ns1:queryResponse'=>[
{
'ns1:result'=>[
{
'ns1:done'=>['true'],
'ns1:queryLocator' => [
{
'xsi:nil' => '1',
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
}
],
'ns1:size' => [
'60'
],
'ns1:records' => [
{
'ns2:RefundTransactionTime' => [
'2013-09-12T13:17:18.000-08:00'
],
'xmlns:ns2' => 'http://object.abccom/',
'ns2:MethodType' => [
'CreditCard'
],
'ns2:Gateway' => [
'Chase Paymentech'
],
'ns2:Type' => [
'Electronic'
],
'ns2:RefundDate' => [
'2013-09-12T00:00:00'
],
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'ns2:Status' => [
'Processed'
],
'ns2:Id' => [
'2c92c0f8410f4d9a014113d2170a2e17'
],
'xsi:type' => 'ns2:Refund',
'ns2:AccountId' => [
'2c92c0f9410f55ee0141132b6c936e15'
],
'ns2:Amount' => [
'99'
],
'ns2:CreatedDate' => [
'2013-09-12T13:17:17.000-08:00'
]
},
{
'xmlns:ns2' => 'http://object.abccom/',
'ns2:MethodType' => [
'CreditCard'
],
'ns2:Type' => [
'External'
],
'ns2:RefundDate' => [
'2013-10-12T00:00:00'
],
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'ns2:Status' => [
'Processed'
],
'ns2:Id' => [
'2c92c0f8410f4d9a0141145bfbb61a9b'
],
'xsi:type' => 'ns2:Refund',
'ns2:AccountId' => [
'2c92c0f8410f4d8701411411a9ad79b7'
],
'ns2:Amount' => [
'477.74'
],
'ns2:CreatedDate' => [
'2013-09-12T15:47:54.000-08:00'
],
'ns2:Comment' => [
'16 Payment Exception - Chargeback'
]
}
]
}
],
'xmlns:ns1' => 'http://api.abccom/'
}
]
}
],
'xmlns:soapenv' => 'http://schemas.xmlsoap.org/soap/envelope/'
};
I am using below code :
#!/usr/bin/env perl
use strict;
use Data::Dumper;
use XML::Simple qw(:strict);
my $data = XMLin('Refund.xml', forcearray=>1, keyattr=>[] );
print "Reference type in data is : ", ref($data), "\n";
print Dumper($data);
#Try to access the values
my $records=$data->{"soapenv:Body"}->[0]->{"ns1:queryResponse"}->[0]->{"ns1:result"}->
[0]->{"ns1:records"};
foreach my $record ( #{ $records } ) {
print $record->{"ns2:RefundTransactionTime"};
print "\n";
}
print Dumper($data) generates hash reference containing array of hashes.
I want to format the hash reference generated above to the array of array references format as shown below:
[
[
"AccountId",
"Id",
"Amount",
"CreatedDate",
"Comment",
"Status",
"Type",
"RefundDate",
"MethodType"
],
[
"2c92c0f8410f4d8701411411a9ad79b7",
"2c92c0f8410f4d9a0141145bfbb61a9b",
"477.74",
"2013-09-12T15:47:54.000-08:00",
"16 Payment Exception - Chargeback",
"Processes",
"External",
"2013-10-12T00:00:00",
"CreditCard"
],
[
"2c92c0f9410f55ee0141132b6c936e15",
"2c92c0f8410f4d9a014113d2170a2e17",
"99",
"2013-09-12T13:17:17.000-08:00",
"",
"Processed",
"Electronic",
"2013-09-12T00:00:00",
"Chase Paymentech"
]
],
Any help is greatly appreciated. Thank you
The return value ARRAY(0x1f9fca98) indicates that $record->{"ns2:RefundTransactionTime"} contains an array reference. You probably want the first element: $record->{"ns2:RefundTransactionTime"}->[0].
this is a dump of my hashes: %hash1
$VAR1 = {
abc => {
123 => [
'xx',
'yy',
'zy'
],
456 => [
'ab',
'cd',
'ef'
]
}
};
and the second one: %hash2
$VAR2 = {
def => {
659 => [
'wx',
'yg',
'kl'
],
456 => [
'as',
'sd',
'df'
]
},
abc => {
987 => [
'lk',
'dm',
'sd'
]
}
};
Now I want to merge these two hashes in a new hash, but if a key is duplicated (here 'abc'), the values should be appended, not replaced, so the keys should remain unique, and all the values should be retained as well. How can this be done in Perl?
The output should be as follows:
$VAR1 = {
def => {
659 => [
'wx',
'yg',
'kl'
],
456 => [
'as',
'sd',
'df'
]
},
abc => {
987 => [
'lk',
'dm',
'sd'
],
123 => [
'xx',
'yy',
'zy'
],
456 => [
'ab',
'cd',
'ef'
]
}
};
Use the CPAN modules Hash::Merge or Hash::Merge::Simple. The first is highly configurable and the second is very simple to use.
for my $x (keys(%h2)) {
for my $y (keys(%{ $h2{$x} })) {
push #{ $h1{$x}{$y} }, #{ $h2{$x}{$y} };
}
}
For the sample data provided, the following would perform the merging you describe:
my %merged = map {
$_ => {
%{$a{$_} // {}},
%{$b{$_} // {}}
}
} ( keys %a, keys %b );
Test:
use strict;
use warnings;
use Data::Dump 'dd';
my %a = (
abc => {
123 => [
'xx',
'yy',
'zy'
],
456 => [
'ab',
'cd',
'ef'
]
}
);
my %b = (
def => {
659 => [
'wx',
'yg',
'kl'
],
456 => [
'as',
'sd',
'df'
]
},
abc => {
987 => [
'lk',
'dm',
'sd'
]
}
);
my %merged = map {
$_ => {
%{$a{$_} // {}},
%{$b{$_} // {}}
}
} ( keys %a, keys %b );
dd \%merged;
# {
# abc => {
# 123 => ["xx", "yy", "zy"],
# 456 => ["ab", "cd", "ef"],
# 987 => ["lk", "dm", "sd"],
# },
# def => { 456 => ["as", "sd", "df"], 659 => ["wx", "yg", "kl"] },
# }
sub merge_hashes {
my ($h1, $h2) = #_;
foreach my $key (keys %$h2) {
if (!exists $h1->{$key} || ref($h1->{$key}) ne 'HASH' || ref($h2->{$key}) ne 'HASH') {
$h1->{$key} = $h2->{$key};
}
else {
merge_hashes($h1->{$key}, $h2->{$key});
}
}
}
merge_hashes(\%hash1, \%hash2);