Iterating through a array of hashes in a hash that has multiple indexes

81 views Asked by At

I am currently writing a perl script that has a few hashes that containing: (Do not take this as lines of codes, it's just to show/explain)

$details{tester_name} is "UFLEX-06"
$details{op_sys} is "Windows"
$details{igxl_vn} is "8.00.01_uflx (P7)"
$details{slot} -> see below for details
$details{board_name} -> see below for details

Now in $details{slot} I have multiple indexes that contain a value each.

$details{slot} [0] has "2"
$details{slot} [1] has "5"

and so on. $details{slot} has the same number of indexes as $details{board_name}.

Now I want to iterate through this but according to $details{slot}.

What I have done so far which iterates through %details only:

foreach my $key(keys %details)
{
    print {$fh} "INSERT INTO TesterDeviceMatrix.TBL_TESTER_INFO"
    ."(tester_name, operating_system , version, board_name , config , date_modified ) "
    ."VALUES ('$details{tester_name}', '$details{op_sys}', '$details{board_name}', "
    ."'$details{igxl_vn}', '$details{slot}', '$timestamp');\n";
}

But what I would like to do is something like

foreach my $key(keys %details{slot}) -> or %details{board_name}
{
    print {$fh} "INSERT INTO TesterDeviceMatrix.TBL_TESTER_INFO"
    ."(tester_name, operating_system , version, board_name , config , date_modified ) "
    ."VALUES ('$details{tester_name}', '$details{op_sys}', '$details{board_name}', "
    ."'$details{igxl_vn}', '$details{slot}', '$timestamp');\n";
}

I know this is wrong but it is just to show my idea of it.

Output I am getting now is:

INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VirtualDSPBrd', '8.00.01_uflx (P7)', '66.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VirtualDSPBrd', '8.00.01_uflx (P7)', '66.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VirtualDSPBrd', '8.00.01_uflx (P7)', '66.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VirtualDSPBrd', '8.00.01_uflx (P7)', '66.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VirtualDSPBrd', '8.00.01_uflx (P7)', '66.0', '2015-06-11 11:15:33');

The above output has 5 lines which because there are 5 hashes. However what I desire is 8 lines with values according to their indexes, as there are 8 indexes for $details{slot} which means there also 8 indexes for $details{board_name}.

An example of my desired output would be (notice value difference and 8 lines):

INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'abcBrd', '8.00.01_uflx (P7)', '2.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VqwelDSPBrd', '8.00.01_uflx (P7)', '5.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'DiffDSPBrd', '8.00.01_uflx (P7)', '8.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', '123DSPBrd', '8.00.01_uflx (P7)', '26.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'V1r12alDSPBrd', '8.00.01_uflx (P7)', '56.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'VMamaBrd', '8.00.01_uflx (P7)', '52.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ONSPBrd', '8.00.01_uflx (P7)', '56.0', '2015-06-11 11:15:33');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'bankaiPBrd', '8.00.01_uflx (P7)', '66.0', '2015-06-11 11:15:33');

So the question is how do I iterate and then print according to how many indexes are in the hash $details{slot} where by $details{slot} and $details{board_name} would be printed according to their indexes?

I understand that I would have to create another for loop inside the current one I have. However, most solutions are for hashes that only contain one value so that's why it doesn't cater to my needs.

EDIT:

(Note: This dump shows only the latest board_name and slot)

{
    board_name => "Virtualabc"
    igxl_vn => "9.0.0_abc"
    op_sys => "Windows"
    slot => "66.0"
    tester_name => "UNFEK-02"
}

EDIT 2:

I've edited my script where by I have declared slot and board_name into arrays as suggested by @shivams.

push @{ $details{slot} }, [$1];
push @{ $details{board_name} }, [$2];

Now as suggested by Dmitry's answer(first part), I am getting the reference to the array only. Here is the output:

INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [0]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [0]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [1]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [1]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [2]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [2]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [3]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [3]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [4]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [4]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [5]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [5]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [6]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [6]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [7]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [7]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [8]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [8]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [9]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [9]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [10]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [10]', '2015-06-11 15:18:37');
INSERT INTO TBL_TESTER_INFO(tester_name, operating_system , version, board_name , config , date_modified ) VALUES ('UFLEX-06', 'Windows XP', 'ARRAY(0x1d2fb98) [11]', '8.00.01_uflx (P7)', 'ARRAY(0x1d40288) [11]', '2015-06-11 15:18:37');

How do I get the exact value?

2

There are 2 answers

6
Dmitry Egorov On BEST ANSWER

You do not actually need to loop through keys %details. I take it, you have built the %details hash based on Borodin's suggestion from Extracting data from log file into Perl hash. In this case what you have is not actually an array of hashes but rather a single hash %details containing two lists in it (among some other scalar values).

In order to prepare the desired set of insert statements from it you should iterate through %details's sublists only. The %details's scalar fields should be accessed directly:

for (my $i = 0; $i < @{$details{slot}}; $i++) {
    print
        "INSERT INTO TesterDeviceMatrix.TBL_TESTER_INFO"
        ."(tester_name, operating_system , version, board_name , config , date_modified ) "
        ."VALUES ('$details{tester_name}', '$details{op_sys}', '$details{board_name}[$i]', "
        ."'$details{igxl_vn}', '$details{slot}[$i]', '$timestamp');\n";
}

Here is a test script illustrating the said above.

UPDATE following EDIT 2:

Change

push @{ $details{slot} }, [$1];
push @{ $details{board_name} }, [$2];

to

push @{ $details{slot} }, $1;
push @{ $details{board_name} }, $2;

Pushing [$var] (i.e. a scalar variable with square brackets) into an array would populate the array with one-element sub-arrays containing this single scalar value each. This is because [$var] constructs a reference to an array containing the single element $var. All you actually need instead is to push the scalar value itself.

P.S.

Consider using parametrized queries instead of hardcoded ones.

7
shivams On
foreach my $key(keys %details) {
 if (ref($key)  eq 'ARRAY') {
   foreach $key2 (@$key) {
      PRINT STATEMENT
   }
 }
 else {
  PRINT STATEMENT
 }
}

In this way when there is array in hash your code will loop on that array through inner foreach loop and if not it will go to else. Also now how you want to use values i totally upon you.