Perl : Printing a hash with multiple values for single key - perl

I have hash with multiple values to a key. How to print multiple values of key in a hash independently?
# HASH with multiple values for each key
my %hash = ( "fruits" => [ "apple" , "mango" ], "vegs" => ["Potato" , "Onion"]);
# SET UP THE TABLE
print "<table border='1'>";
print "<th>Category</th><th>value1</th><th>value2</th>";
#Print key and values in hash in tabular format
foreach $key (sort keys %hash) {
print "<tr><td>".$key."</td>";
print "<td>".#{$hash{$key}}."</td>";
}
* Current Output: *
Category Value1 Value2
fruits apple mango
vegs Potato Onion
* Desired Output: *
Category Value1 Value2
fruits apple mango
vegs Potato Onion

Try replacing the second line of your loop with
print "<td>$_</td>" for #{ $hash{$key} };
Which will loop over each item in the array reference and wrap them in td tags.

Related

Logical solution for nested for loop

I have a bit of logic drain. I hope I can explain what I am missing and what I want in a coherent manner. Let me know if I have to add a bit more data or information.
I have an Excel spreadsheet which I am trying to load to a database. I have slurped the data into an array of hashes. The data in the array looks like this
$hash_of_excel = [
{
col1 => 'value1',
col2 => 'value2',
col3 => 'value3|value4',
col4 => 'value5|value6|value7',
},
{
col1 => 'value8',
col2 => 'value9',
col3 => 'value10|value11|value12',
col4 => 'value13|value14|value15',
},
{
col1 => 'value16|value17',
col2 => 'value19|value18',
col3 => 'value20',
col4 => 'value21',
}
]
I have a piece of code that walks this data structure to get the values
foreach my $results ( #$hash_of_excel ) {
for my $colname ( sort keys %$results ) {
my #array = split /\|/, $results->{$colname};
foreach my $value ( #array ) {
warn $results->{'col1'}, $results->{'col2'}, $results->{'col3'};
last;
}
}
last if $counter++ == 2;
}
This would result in the same value printing over and over for the number of columns present in each hash (ie 4 in our case).
How can I access different columns for the DBI insert but without having to go through lot of for loops?
Is there a way to check if the value has more than one value and pushing them to array instead of having to get all of them in an array?
Or is this good to hand the database inserts to a subroutine and pass just the required column values in an array?
It's not clear what exactly you want, but your innermost loop is weird: it iterates over #array with $value, but $value isn't used in it - that's why you're getting the same output for all the iterations.
The following loop outputs all the values instead:
foreach my $value (#array){
warn $value;
}
i.e. no $results, no last.

for loop in hash table printing only last value

Please advice.
for my $record (#item) {
for my $int (#$record){
# DEBUG( "DEBUG:: $record and $int");
my %data = ( $record , $int );
}
}
}
Record is like
abc ,china
abc ,japan
abc , italy
abc , singapore
print Dumper %data;
output :
abc , singapore
Now the issues is when I dump the output it shows me last record entry in hash table.May be because of unique key.
Kindly suggest.
Two problems:
You are recreating the hash in each iteration of the loop. The correct way would be
my %data;
for my $record (#item) {
for my $int (#$record){
$data{$record} = $int;
}
}
Hash keys must be unique. It's not possible to have a hash like
( abc => 'china',
abc => 'japan' )
You can use a hash of arrays, though. Just assign to it with
push #{ $data{$record} }, $int;
It will create the following structure:
( abc => [ 'china', 'japan', 'italy', 'singapore' ] )

XML File Creation in Perl - Updated Requirements [duplicate]

This question already has answers here:
XML file creation in Perl
(2 answers)
Closed 8 years ago.
Sorry, I am posting this again but lot of requirements have been changed and I need advice.
My First input file is
Root1 TBLA KEY1 COLA A B
Root1 TBLA KEY1 COLB D E
Root1 TBLA KEY3 COLX M N
Root2 TBLB KEY4 COLX M N
Root2 TBLB KEY4 COLD A B
Root3 TBLC KEY5 COLD A B
My second input file is
Root1 TBLA KEY6
Root2 TBLB KEY7
Root3 TBLC KEY8
My third input file is
Root1 TBLA KEY9
Root1 TBLA KEY10
Root3 TBLC KEY11
Basically File representation is
1) First file represents the old and new values. First is root table, Second is actual table in which diff is there. Third column tells the key value. Fourth and Fifth represents old and new value.
2) Second file represents the primary key which exists in db1 only and not in db2. First is root table, Second is actual table in which key exists. Third column tells the key value
3) Third file represents the primary key which exists in db2 only and not in db1. First is root table, Second is actual table in which key exists. Third column tells the key value
The output to be created in xml format as
<Data>
<Root1>
<TBLA>
<NEW1>
<KEY>KEY6</KEY>
<NEW1>
<NEW2>
<KEY>KEY9</KEY>
<KEY>KEY10</KEY>
<NEW2>
<MODIFIED>
<KEY name =KEY1>
<COLA>
<oldvalue>A</oldvalue>
<newvalue>B</newvalue>
</COLA>
<COLB>
<oldvalue>D</oldvalue>
<newvalue>E</newvalue>
</COLB>
</KEY>
<KEY name =KEY3>
<COLX>
<oldvalue>M</oldvalue>
<newvalue>N</newvalue>
</COLX>
</KEY>
</MODIFIED>
</TBLA>
</Root1>
<Data>
THIS IS NOT COMPLETE OUTPUT. PART OF OUTPUT IS DISPLAYED
Can anyone suggest what would be the best way to do this. Should i convert this text file to hash of hashes first and then try using pltoxml(). does this make sense. Can XML::Simple or XML::Writer suffice this.
This is the first time I am working on xml and not sure which approach will help efficicently my solution.
A small example wrt to my req would be appreciated.
*Input file will always be sorted on Root and then TBLNAME
Output format
Output contains for every root, every table in that root and that for every table, key which exists in one and then key which exists in second only. This comes in section new1 and new2 respectively. Third section contains Modified which needs to read from first input file and list the key value and with that key value what columns are modified (their old and new value)
If I have to use XML::Simple, how do i create hashref from these files which i can pass it to XMLout. There is no key in any of these files.
This is simply a matter of using split to split the data into fields, storing it into a hash and then transforming it using XML::Simple.
Note that I stick things into an array to enforce the order you intended.
All the data is read from the DATA handle. You shouldn't need me to show you IO code.
The #processors array is simply the different processors you would use on the various files:
Code:
use 5.016;
use strict;
use warnings;
use XML::Simple qw(:strict);
my %roots;
my #processors
= ( sub {
my ( $root, $table, $key, $col, $old, $new ) = split /\s+/;
$roots{ $root }{ $table }[2]{MODIFIED}{ $col }
= { oldvalue => $old
, newvalue => $new
};
return;
}
, sub {
my ( $root, $table, $key ) = split /\s+/;
push #{ $roots{ $root }{ $table }[0]{NEW1}{KEY} }, $key;
}
, sub {
my ( $root, $table, $key ) = split /\s+/;
push #{ $roots{ $root }{ $table }[1]{NEW2}{KEY} }, $key;
}
);
my $processor = shift #processors;
while ( <> ) {
chomp;
if ( $_ eq '---' ) {
$processor = shift #processors;
}
else {
$processor->( $_ );
}
}
my $xs = XML::Simple->new( NoAttr => 1, RootName => 'Data', );
my $xml = $xs->XMLout( \%roots, KeyAttr => {} );
say $xml;
It produces:
<Data>
<Root1>
<TBLA>
<NEW1>
<KEY>KEY6</KEY>
</NEW1>
</TBLA>
<TBLA>
<NEW2>
<KEY>KEY9</KEY>
<KEY>KEY10</KEY>
</NEW2>
</TBLA>
<TBLA>
<MODIFIED>
<COLA>
<newvalue>B</newvalue>
<oldvalue>A</oldvalue>
</COLA>
<COLB>
<newvalue>E</newvalue>
<oldvalue>D</oldvalue>
</COLB>
<COLX>
<newvalue>N</newvalue>
<oldvalue>M</oldvalue>
</COLX>
</MODIFIED>
</TBLA>
</Root1>
<Root2>
<TBLB>
<NEW1>
<KEY>KEY7</KEY>
</NEW1>
</TBLB>
<TBLB></TBLB>
<TBLB>
<MODIFIED>
<COLD>
<newvalue>B</newvalue>
<oldvalue>A</oldvalue>
</COLD>
<COLX>
<newvalue>N</newvalue>
<oldvalue>M</oldvalue>
</COLX>
</MODIFIED>
</TBLB>
</Root2>
<Root3>
<TBLC>
<NEW1>
<KEY>KEY8</KEY>
</NEW1>
</TBLC>
<TBLC>
<NEW2>
<KEY>KEY11</KEY>
</NEW2>
</TBLC>
<TBLC>
<MODIFIED>
<COLD>
<newvalue>B</newvalue>
<oldvalue>A</oldvalue>
</COLD>
</MODIFIED>
</TBLC>
</Root3>
</Data>

How to write hash key and value pairs into MongoDB documents as field values in Perl?

my %Hash= (2012=> 1, 1982=>12, 2010=>0);
The has key and values need to be all on the same field name 'time' like an array
$mycollection->insert(
{
'field1' => $var1;
'field2' => $var2;
#right here I need to know how to add above hash key and values
# like below
#'time': ["2012.1","1982.12","2010.0"]
}
);
Any suggestions or ideas will be apprecieated. This can probably accomplished by doing series of update statements but I would like to accomplish this with one insert statement due to my requirement.
I suppose your %Hash variable is something like this:
my %Hash= (2012=> 1, 1982=>12, 2010=>0);
So your array "time" is build this way:
my #time = map { $_ . "." . $Hash{$_} } keys %Hash;
and finally:
$mycollection->insert({
'field1' => $var1,
'field2' => $var2,
'time' => \#time
});

Using Perl's DBI, how can join the results of fetchrow_arrayref?

I am new to Perl, and I am writing a script to fetch some rows from a database:
my #rows = $conn->fetchrow_array(1,2,3);
the result will be three rows of single column.
12345
56789
12376
How should I join them together as 12345,56789,56789
I tried,
my $list = join ",", #rows.
Result: ARRAY(0x14f6de0),ARRAY(0x1508a90),ARRAY(0x15014c0)
Going through a foreach loop just print the results with a new line:
12345
56789
12376
What am I doing wrong ? have I got the concept of fetchrow_array wrong?
Each row is a reference to an array (because each row could contain multiple columns). Something like the following should work.
#!/usr/bin/perl
use strict; use warnings;
my #rows = (
[ 12345 ],
[ 56789 ],
[ 12376 ],
);
my #vals = map #$_, #rows;
print join(',', #vals), "\n";
However, you are better off using selectcol_arrayref:
This utility method combines "prepare", "execute", and fetching one column from all the rows, into a single call. It returns a reference to an array containing the values of the first column from each row.