manipulating a hash of hashes

Discussion in 'Perl Misc' started by Aaron DeLoach, Jul 7, 2004.

  1. Hi all,

    I have the following HoH:

    my %payment_methods =
    (
    "Credit Cards"=>{
    "ae" => "American Express",
    "di" => "Discover",
    "vi" => "Visa",
    "jc" => "JCB",
    "dc" => "Diners Club",
    "mc" => "MasterCard",
    },
    "Other"=>{
    "mo" => "Money Order",
    "po" => "Purchase Order",
    },
    "Checks"=>{
    "pe" => "Personal Check",
    "co" => "Company Check",
    "ca" => "Cashiers Check",
    "ce" => "Certified Check",
    },
    );

    I would like to construct an html table of the data as follows. I don't need
    help with the html, just the ability to produce the data in column/row
    format.

    (hash names)
    row1 Credit Cards | Other | Check
    (now values)
    row2 American express | Money Order | Company Check
    row3 Discover | Purchase Order | Cashiers Check
    row4 Visa | | Certified Check
    row5 JCB | |
    row6 Diners Club | |

    and so on...

    As you can see from the example data ends in different columns as the hash
    runs out of values. Any assistance would be greatly appreciated.

    Regards
    Aaron
     
    Aaron DeLoach, Jul 7, 2004
    #1
    1. Advertising

  2. Aaron DeLoach

    Paul Lalli Guest

    On Wed, 7 Jul 2004, Aaron DeLoach wrote:

    > Hi all,
    >
    > I have the following HoH:
    >
    > my %payment_methods =
    > (
    > "Credit Cards"=>{
    > "ae" => "American Express",
    > "di" => "Discover",
    > "vi" => "Visa",
    > "jc" => "JCB",
    > "dc" => "Diners Club",
    > "mc" => "MasterCard",
    > },
    > "Other"=>{
    > "mo" => "Money Order",
    > "po" => "Purchase Order",
    > },
    > "Checks"=>{
    > "pe" => "Personal Check",
    > "co" => "Company Check",
    > "ca" => "Cashiers Check",
    > "ce" => "Certified Check",
    > },
    > );
    >
    > I would like to construct an html table of the data as follows. I don't need
    > help with the html, just the ability to produce the data in column/row
    > format.
    >
    > (hash names)
    > row1 Credit Cards | Other | Check
    > (now values)
    > row2 American express | Money Order | Company Check
    > row3 Discover | Purchase Order | Cashiers Check
    > row4 Visa | | Certified Check
    > row5 JCB | |
    > row6 Diners Club | |
    >
    > and so on...
    >
    > As you can see from the example data ends in different columns as the hash
    > runs out of values. Any assistance would be greatly appreciated.



    Don't try to do what's already been done before. Use a module that's
    already written, like HTML::Table, available on CPAN:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use HTML::Table
    my %payment_methods =
    (
    "Credit Cards"=>{
    "ae" => "American Express",
    "di" => "Discover",
    "vi" => "Visa",
    "jc" => "JCB",
    "dc" => "Diners Club",
    "mc" => "MasterCard",
    },
    "Other"=>{
    "mo" => "Money Order",
    "po" => "Purchase Order",
    },
    "Checks"=>{
    "pe" => "Personal Check",
    "co" => "Company Check",
    "ca" => "Cashiers Check",
    "ce" => "Certified Check",
    },
    );

    my $table = new HTML::Table;
    foreach $type (keys %payment_methods) {
    $table->addCol($type, values(%{$payment_methods{$type}}));
    }

    print $table->getTable, "\n";

    __END__

    (note that formatting, for example the column headings, is left as an
    excercise to the reader. It should be possible once you've read the
    documentation for HTML::Table)

    Paul Lalli
     
    Paul Lalli, Jul 7, 2004
    #2
    1. Advertising

  3. [posted & mailed]

    On Wed, 7 Jul 2004, Aaron DeLoach wrote:

    [reformatted]
    >Credit | Other | Check
    >===========================================
    >AmEx | Money Order | Company Check
    >Disc | Purchase Order | Cashiers Check
    >Visa | | Certified Check
    >JCB | | Personal Check
    >Diner | |


    >As you can see from the example data ends in different columns as the hash
    >runs out of values. Any assistance would be greatly appreciated.


    I would first get the data out of the hashrefs:

    my @data = map [values %$_], values %payment_methods;

    This gets us from:

    my %payment_methods = (
    "Credit Cards" => {
    "ae" => "American Express",
    "di" => "Discover",
    "vi" => "Visa",
    "jc" => "JCB",
    "dc" => "Diners Club",
    "mc" => "MasterCard",
    },
    "Other"=>{
    "mo" => "Money Order",
    "po" => "Purchase Order",
    },
    "Checks"=>{
    "pe" => "Personal Check",
    "co" => "Company Check",
    "ca" => "Cashiers Check",
    "ce" => "Certified Check",
    },
    );

    to this:

    @data = (
    [ "American Express", "Discover", "Visa", ... ],
    [ "Money Order", "Purchase Order" ],
    [ "Personal Check", "Company Check", ... ],
    );

    though not necessarily in those orders. Now we need to know the dimension
    of the largest hashref (now arrayref):

    my $max = 0;
    for (@data) { $max = @$_ if $max < @$_ }

    Now we can do this in a naive manner or a more cunning manner:

    print "<table>\n";
    for my $i (0 .. $max-1) {
    print "<tr>\n";
    for (@data) {
    print "<td>$_->[$i]</td>";
    }
    print "\n</tr>\n";
    }
    print "</table>\n";

    That's naive, because you'll be getting empty cells whenever an arrayref
    "runs out" of elements. The more cunning way is to insert "rowspan"
    attributes when an array is on its last element, and then to skip that
    array afterwards.

    print "<table>\n";
    for my $i (0 .. $max-1) {
    print "<tr>\n";
    for (@data) {
    # skip if we're past the end
    next if $#$_ < $i;

    # if this is the last element, make its rowspan bigger
    my $span = ($#$_ == $i) ? $max - $#$_ : 1;

    print "<td rowspan=$span valign='top'>$_->[$i]</td>";
    }
    print "\n</tr>\n";
    }
    print "</table>\n";

    --
    Jeff "japhy" Pinyan % How can we ever be the sold short or
    RPI Acacia Brother #734 % the cheated, we who for every service
    RPI Corporation Secretary % have long ago been overpaid?
    http://japhy.perlmonk.org/ %
    http://www.perlmonks.org/ % -- Meister Eckhart
     
    Jeff 'japhy' Pinyan, Jul 7, 2004
    #3
  4. Aaron DeLoach

    Brad Baxter Guest

    On Wed, 7 Jul 2004, Aaron DeLoach wrote:

    > Hi all,
    >
    > I have the following HoH:
    >
    > my %payment_methods =
    > (
    > "Credit Cards"=>{
    > "ae" => "American Express",
    > "di" => "Discover",
    > "vi" => "Visa",
    > "jc" => "JCB",
    > "dc" => "Diners Club",
    > "mc" => "MasterCard",
    > },
    > "Other"=>{
    > "mo" => "Money Order",
    > "po" => "Purchase Order",
    > },
    > "Checks"=>{
    > "pe" => "Personal Check",
    > "co" => "Company Check",
    > "ca" => "Cashiers Check",
    > "ce" => "Certified Check",
    > },
    > );
    >
    > I would like to construct an html table of the data as follows. I don't need
    > help with the html, just the ability to produce the data in column/row
    > format.
    >
    > (hash names)
    > row1 Credit Cards | Other | Check
    > (now values)
    > row2 American express | Money Order | Company Check
    > row3 Discover | Purchase Order | Cashiers Check
    > row4 Visa | | Certified Check
    > row5 JCB | |
    > row6 Diners Club | |
    >
    > and so on...
    >
    > As you can see from the example data ends in different columns as the hash
    > runs out of values. Any assistance would be greatly appreciated.
    >
    > Regards
    > Aaron


    Below is another solution using a module. I cheated and used 'sort' in a
    couple of places. If you really want the order you show above, then
    replace sort with a different method. :)


    use Array::Each;

    my @headings = sort keys %payment_methods;

    my $set = Array::Each->new(
    set => [ map [sort values %$_],
    @payment_methods{ @headings }, ],
    undef => '&nbsp;',
    bound => 0,
    count => 1,
    );

    print
    "<table border='1'>\n",
    "<tr> <td></td>",
    map( "<th>$_</th> ", @headings ),
    "</tr>\n";
    while( my @row = $set->each ) {
    printf "<tr> <td>row%d.</td> ", pop @row;
    print map( "<td>$_</td> ", @row ), "</tr>\n";
    }
    print "</table>\n";



    Regards,

    Brad

    --
    http://search.cpan.org/~bbaxter/Array-Each-0.02/Each.pm
     
    Brad Baxter, Jul 7, 2004
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. rp
    Replies:
    1
    Views:
    582
    red floyd
    Nov 10, 2011
  2. Scott  Gilpin
    Replies:
    2
    Views:
    236
  3. Perl Learner

    Hashes of hashes or just one hash ?

    Perl Learner, Jun 8, 2005, in forum: Perl Misc
    Replies:
    11
    Views:
    232
  4. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    233
  5. Replies:
    3
    Views:
    233
Loading...

Share This Page