PriNet has asked for the wisdom of the Perl Monks concerning the following question:

I have been experimenting with several adaptations of 'grep' to try and find the key value of a multidimensional hash... If anyone can propose a solution, please do before I lose all my sanity. Here is a snipit of the array and the result I'm trying to end up with:
my(%DetailSheet) = ( 'ColumnName' => { 'ID' => { 'PositionAdjustment' => 0, 'RecordName' => 'Identification', 'RecordNumber' => 0, 'RecordValue' => '', 'XlsName' => 'Reference', 'XlsColumn' => 1, 'XlsFormat' => '', 'XlsWidth' => 15, 'XlsLock' => 1, 'GuiName' => 'Number', 'GuiNumber' => 2, 'GuiValue' => '', 'Switch' => [ ['O','0'], ['l','1'] ] }, 'DESCRIPTION' => { 'PositionAdjustment' => 0, 'RecordName' => 'Description', 'RecordNumber' => 1, 'RecordValue' => '', 'XlsName' => 'Description', 'XlsColumn' => 2, 'XlsFormat' => '', 'XlsWidth' => 15, 'XlsLock' => 1, 'GuiName' => 'Description', 'GuiNumber' => 3, 'GuiValue' => '', 'Switch' => [ [' AND ', ' & '], [' WITH ', ' W/ '] ] } } );

What I'm attempting is to get the key value 'DESCRIPTION' by searching for the value '2' in the 'XlsColumn' key/value pair. I'm sure grep can be used to do this, I just don't know how to implement it. Of course I could do a for loop ant itterate over each pair until i find where 'XlsColumn is 2', then extract the 'DISCRIPTION' key where I found it, but, I'm thinking grep would be a much simpler and less code approach.
Thanx ahead for any 2-bits that might come back...

I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...

Replies are listed 'Best First'.
Re: grep confusion
by tybalt89 (Monsignor) on Sep 01, 2017 at 03:26 UTC
    #!/usr/bin/perl -l # http://perlmonks.org/?node_id=1198481 use strict; use warnings; my %DetailSheet = ( 'ColumnName' => { 'ID' => { 'PositionAdjustment' => 0, 'RecordName' => 'Identification', 'RecordNumber' => 0, 'RecordValue' => '', 'XlsName' => 'Reference', 'XlsColumn' => 1, 'XlsFormat' => '', 'XlsWidth' => 15, 'XlsLock' => 1, 'GuiName' => 'Number', 'GuiNumber' => 2, 'GuiValue' => '', 'Switch' => [ ['O','0'], ['l','1'] ] }, 'DESCRIPTION' => { 'PositionAdjustment' => 0, 'RecordName' => 'Description', 'RecordNumber' => 1, 'RecordValue' => '', 'XlsName' => 'Description', 'XlsColumn' => 2, 'XlsFormat' => '', 'XlsWidth' => 15, 'XlsLock' => 1, 'GuiName' => 'Description', 'GuiNumber' => 3, 'GuiValue' => '', 'Switch' => [ [' AND ', ' & '], [' WITH ', ' W/ '] ] } } ); print grep { $DetailSheet{ColumnName}{$_}{XlsColumn} == 2 } keys %{ $DetailSheet{ColumnName} };

    Outputs:

    DESCRIPTION
      Ok, I'm not sure what happend, but I used your reference tybalt89 and I think I got the result I was after... grep does work! thanx a gigabyte, I'm going to continue with my program now (it kinda got more complicated than I thought when I started the project)... thanx again guys, given the time and enough twinkies, you guys have come through for me again...
      -Gary

      I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...
        tybalt89 's and my solution are identical as far as I see.

        The only difference is he included the provided data in his example, and you are most probably running my code against broken data.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Re: grep confusion
by LanX (Saint) on Sep 01, 2017 at 02:07 UTC
    Something like

    print grep { $DetailSheet{ColumnName}{$_}{XlsColumn} == 2 } keys %{$DetailSheet{ColumnName}} ?

    (Untested)

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

    update

    Added ColumnName level

      The function first_value (from List::MoreUtils) is slightly better than grep because it returns the single value that you expect as a scalar.
      use strict; use warnings; use List::MoreUtils qw(first_value); my(%DetailSheet) = ( ... ); my %Column = %{$DetailSheet{ColumnName}}; my $description = first_value {$Column{$_}{XlsColumn} == 2} keys %Colu +mn; print $description, "\n";
      Bill
        IMHO it's unclear from the OP s description how many results he expects.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

        I will need to look into that Bill, I'm always looking for shortcuts !

        I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...
      Hmmm... 'Error: Not a HASH reference'
      but I see where your going...

      I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...
        wait... let me try that

        I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...
Re: grep confusion
by thanos1983 (Parson) on Sep 01, 2017 at 09:02 UTC

    Hello PriNet,

    It seems the fellow Monks have provided you with solutions. I tried to retrieve the key without using grep but is seems that is more efficient to use it instead of not.

    Sample of test code and Benchmark results:

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      I did finally get the grep to work as expected thanos1983, again, like I mentioned above, I'm begining to think my environment for perl is causing gremlins, I may fire up an old windows xp machine by itself to do my testing on, I'm begining to think the virtual machine's limitations are being exceeded... previously correct/good/executable lines in my code that worked before I kept adding more script are starting to throw errors... thanx again everyone for your guidance, maybe someday I can actually help someone else *heh*
      -Gary

      I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...
        I believe I found out what's causing my 'arbitrary' errors (they only happen sometimes). So here's an update and I welcome any resolutions anyone may have:
        I use pdf2text to convert some (work) files to an xls worksheet
        everything was going fine until I wrote in an 'opportunity' to edit the XLS file before continuing on with my script.
        I use Spreadsheet::WriteExcel; to create the initial XLS (works fine)
        I then use
        system('C:/Progra~1/OpenOf~1/Program/Scalc "'.$CurrentDirectory.'/Resources/'.$Filename.'"');
        (which also works fine) to start OpenOffice for the 'editing' option
        then directly after that I (using)
        use Spreadsheet::ParseExcel::SaveParser;
        start reading the file with the line:
        $XlsWorkbook = Spreadsheet::ParseExcel::SaveParser->new()->Parse($CurrentDirectory.'/Resources/'.$Filename);
        to 'reload' the file to update my 'optional' changes...
        I am under the impression (because it only happens 'sometimes') that when I close the file in OpenOffice, my script does not 'wait' long enough for the file to completely close in OpenOffice... thus I end up trying to read cells that haven't been defined yet because OpenOffice hasn't finished closing the file.
        I am (of course) going to play with 'sleep' to see if I can slow things down in my script, but, I read in several places that 'sleep' is kinda dangerous in scripts.
        Here's the question: is there a way to tell when OpenOffice has actually completed the close operation before trying to read the file again ?
        I have looked around and found that the 'system' command I use can be modified for different actions and found this:
        system(`nmon -F file.out -s3 -c1`);
        I'm not fluent with the 'system' command and I can't seem to find much information on 'system' command options on the net, should i attempt to play around with this suggestion to see if I can make it work ? -or- is there a module somewhere that I can use to 'watch' OpenOffice' and ensure the XLS file has completely finished/closed/saved before trying to read in the 'changes'?
        I REALLY hope I explained things well enough here. I'll be holding a tin can out for anyone's two-bits...

        I tried re-inventing the wheel again, but everytime I push it, it still falls flat on it's side...