Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Building a data structure - %HoH, %HoA?

by Roboz (Novice)
on Nov 01, 2012 at 11:47 UTC ( #1001808=perlquestion: print w/ replies, xml ) Need Help??
Roboz has asked for the wisdom of the Perl Monks concerning the following question:

Perl Monks, I'm having trouble building a data structure that I can easily retrieve information from later in my code. Given a delimited data file like so:

team_1, location_2, tool_1, 4 team_3, location_1, tool_3, 3 team_2, location_3, tool_3, 2 team_2, location_4, tool_2, 5 team_2, location_4, tool_5, 3

Each team can be in one or more location with one or more tool type. The 4th field is the number of tools. I'd like to eventually generate XML with the following format:

<ToolLocations> <ToolLocation> <LocationName>location_4</LocationName> <ToolList> <Tool> <ToolName>tool_2</ToolName> <ToolNum>5</ToolNum> </Tool> <Tool> <ToolName>tool_5</ToolName> <ToolNum>3</ToolNum> </Tool> </ToolList> </ToolLocation> </ToolLocations>

I believe I need to make a hash of team containing an array of (unique)location containing an array of tools and their number. Or maybe a hash of hashes of hashes?
I've been trying just about every permutation I can think of for days. This seems to work for building one without error, but it doesn't seem right:

(my $team, my $loc, my $tool, my $amt) = (split /[,]/)[1,2,3,4]; $status{$team}{$loc}{$tool}{amt} = $amt;

How would you deal with this? Thanks.

Comment on Building a data structure - %HoH, %HoA?
Select or Download Code
Re: Building a data structure - %HoH, %HoA?
by BrowserUk (Pope) on Nov 01, 2012 at 12:27 UTC
    I believe I need to make a hash of team containing an array of (unique)location containing an array of tools and their number. Or maybe a hash of hashes of hashes? I've been trying just about every permutation I can think of for days.

    Pass your required output to an XML parser that uses data structures and see what it produces; and then mimic it:

    #! perl -slw use strict; use Data::Dump qw[ pp ]; use XML::Simple; my $xml = XMLin( \*DATA, KeepRoot => 1, NoAttr => 1 ); pp $xml; print XMLout( $xml, KeepRoot => 1, NoAttr => 1 ); __DATA__ <ToolLocations> <ToolLocation> <LocationName>location_4</LocationName> <ToolList> <Tool> <ToolName>tool_2</ToolName> <ToolNum>5</ToolNum> </Tool> <Tool> <ToolName>tool_5</ToolName> <ToolNum>3</ToolNum> </Tool> </ToolList> </ToolLocation> </ToolLocations>

    Produces:

    C:\test>1001808 { ToolLocations => { ToolLocation => { LocationName => "location_4", ToolList => { Tool => [ { ToolName => "tool_2", ToolNum => 5 }, { ToolName => "tool_5", ToolNum => 3 }, ], }, }, }, } <ToolLocations> <ToolLocation> <LocationName>location_4</LocationName> <ToolList> <Tool> <ToolName>tool_2</ToolName> <ToolNum>5</ToolNum> </Tool> <Tool> <ToolName>tool_5</ToolName> <ToolNum>3</ToolNum> </Tool> </ToolList> </ToolLocation> </ToolLocations>

    That takes your required output as input, converts it to a data structure and then converts it back successfully. So now you know what the data structure needs to look like.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

Reading your input
by space_monk (Chaplain) on Nov 01, 2012 at 13:21 UTC
    You're reading in CSV data, and some of it may contain comma's and other pesky characters. I am presuming that for example, strings like location_4 would be something like "London, England" in the real data.

    So use CPAN libraries such as Text::CSV to read your CSV data instead of simply reading it line by line and using split

Re: Building a data structure - %HoH, %HoA?
by Anonymous Monk on Nov 01, 2012 at 23:57 UTC
    Why not use an SQLite database file with one or more tables in it?
Re: Building a data structure - %HoH, %HoA?
by sundialsvc4 (Monsignor) on Nov 02, 2012 at 02:06 UTC

    It might help to consider that the notion of references can really be your best-friend.   Feel Free™ to have any number of references to the same bit of data.   If you need to very-quickly locate pieces of data based on multiple, non-unique, key values, you could (for example) easily create a hashref which points to an arrayref containing references to the same bits of data ... which, in the end, only occur in-memory once.

Re: Building a data structure - %HoH, %HoA?
by Anonymous Monk on Nov 02, 2012 at 07:52 UTC

    Could be done via both Hash of Hashes as well as Hash of Arrays

    See if this works....

    Input File

    team_1, location_2, tool_1, 4 team_3, location_1, tool_3, 3 team_2, location_3, tool_3, 2 team_2, location_4, tool_2, 5 team_3, location_2, tool_5, 3 team_1, location_1, tool_3, 1 team_2, location_4, tool_5, 6 team_4, location_2, tool_5, 3 team_5, location_4, tool_4, 2 team_2, location_4, tool_5, 3 team_3, location_3, tool_4, 4 team_2, location_4, tool_5, 3 team_4, location_1, tool_1, 1 team_1, location_3, tool_5, 3 team_3, location_2, tool_5, 5

    Code

    use v5.14; use Data::Dumper; my %locHash; foreach(`cat dataFile`){ my ($locName, $toolName, $toolNum)=(split(/\,/,))[1..3]; $locHash{$locName}->{$toolName}=$toolNum; } print "Data::Dumper:\n"; print Dumper(\%locHash); say "<ToolLocations>"; foreach my $locName(sort keys %locHash){ say " <ToolLocation>"; say " <LocationName>",chomp($locName),"</LocationName>"; say " <ToolList>"; foreach my $toolDetail(sort keys %{$locHash{$locName}}){ say " <Tool>"; say " <ToolName>",chomp($toolDetail),"</ToolName>"; say " <ToolNum>",chomp($locHash{$locName}->{$toolDet +ail}),"</ToolNum>"; say " </Tool"; } say " </ToolList>"; say " </ToolLocation>"; } say "</ToolLocations>";

    Output

    Data::Dumper: $VAR1 = { ' location_1' => { ' tool_3' => ' 1 ', ' tool_1' => ' 1 ' }, ' location_3' => { ' tool_5' => ' 3 ', ' tool_3' => ' 2 ', ' tool_4' => ' 4 ' }, ' location_4' => { ' tool_5' => ' 3 ', ' tool_2' => ' 5 ', ' tool_4' => ' 2 ' }, ' location_2' => { ' tool_5' => ' 5 ', ' tool_1' => ' 4 ' } }; <ToolLocations> <ToolLocation> <LocationName>0</LocationName> <ToolList> <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool </ToolList> </ToolLocation> <ToolLocation> <LocationName>0</LocationName> <ToolList> <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool </ToolList> </ToolLocation> <ToolLocation> <LocationName>0</LocationName> <ToolList> <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool </ToolList> </ToolLocation> <ToolLocation> <LocationName>0</LocationName> <ToolList> <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool <Tool> <ToolName>0</ToolName> <ToolNum>1</ToolNum> </Tool </ToolList> </ToolLocation> </ToolLocations>
Re: Building a data structure - %HoH, %HoA?
by Jenda (Abbot) on Nov 02, 2012 at 10:18 UTC
    (my $team, my $loc, my $tool, my $amt) = (split /[,]/)[1,2,3,4];
    should be
    my ($team, $loc, $tool, $amt) = (split /[,]/)[0,1,2,3];
    or
    my ($team, $loc, $tool, $amt) = split /[,]/;

    The index of the first element of an array/list is 0, not 1!

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1001808]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (11)
As of 2014-08-29 22:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (289 votes), past polls