http://www.perlmonks.org?node_id=927226


in reply to Re^4: Perl Hashes, keys under keys (I think)?
in thread Perl Hashes, keys under keys (I think)?


Hey hbm, thanks for the reply.

I tried reading the data into the hash at first but it was just confusing the crap out of me (trying to use @_ or $_ and also $line) so I did the array thing just to get myself started. Once I get more comfortable with hashes, most likely by the end of this, I will probably go back and change it to what you suggested.

haha Yeah your right, I guess it is pointless to use "join" when only joining 2 elements. Good point, thanks.


I was working on this thing below that I am kinda stuck on. Maybe you could see what I am not doing right.
What I want to do is: I have this new SUB, also a new array (@colLens used this method before with a 2D-Array and it worked good). @colLens has 0..7 elements, same as the amount of fields per each record.

What it will do is, loop through the hash and if the current hash element's length is greater than the value in the same position in @colLens, then that element in @colLens will now big the bigger of the two. So the end effect will be that @colLens holds the largest length of each hash element 0..7 .


Here's what I tried:
my @header = ("RECORD_ID", "STATUS", "PID", "TIME", "DATE", "HELD/WAIT +ING", "FILENAME", "USER"); my @colLens; sub getColumnLengths() { for (my $y = 0; $y <= $#header; $y++) { $colLens[$y] = length($header[$y]); } my $x; # $rec1 = RECORD_ID for my $rec1 ( keys %records ) { $x = 0; if (int($colLens[$x]) < length($rec1)) { $colLens[$x] = length($rec1); } # $rec2 = STATUS for my $rec2 ( keys %{ $records{$rec1} } ) { $x = 1; if (int($colLens[$x]) < length($rec2)) { $colLens[$x] = length($rec2); } $x++; # $rec3 = PID, TIME, DATE, ELAPSED, FILENAME, USER for my $rec3 ( keys %{$records{$rec1}{$rec2}} ) { if (int($colLens[$x]) < int(length($rec3))) { $colLens[$x] = int(length($rec3)); } $x++; }#END INNER-MOST }#END MID }#END OUTER }

From my output I get it seems that it is working for just the first 2 elements, not sure why the rest isn't? I'm assuming it is something with my inner-most loop...


If you can think of anything please let me know.

Thanks in Advance,
Matt

Replies are listed 'Best First'.
Re^6: Perl Hashes, keys under keys (I think)?
by hbm (Hermit) on Sep 22, 2011 at 13:59 UTC

    I don't quite understand what you are doing here, but generally you ought to avoid nested loops. I suspect this for-for-for can be achieved earlier, when you are first building %records.

    But as you have it, confirm what is happening with temporary print statements before each of your assignments:

    if (int($colLens[$x]) < length($rec1)) { printf "colLens:%s, rec1:%s\n", $colLens[$x], $rec1; $colLens[$x] = length($rec1); ...

    Also, stylistically, instead of:

    for (my $y = 0; $y <= $#header; $y++) { $colLens[$y] = length($header[$y]); }

    Consider:

    @colLens = map length, @header;

    I look forward to your final, working program!

    Update: I also meant to say, you have int(length(...)) in a few places. length returns an integer, so no need to wrap it with int.


      hbm, thanks for the reply.
      Nice I like that one you suggested: @colLens = map length, @header; cool stuff!


      I had did what you suggested about the print statements inside each looping area, but I had removed them when I copy/pasted it over to the post, just to make it a little easier to read. And what I noticed was that the first 2 loops where giving the correct lengths but everything after that was not.
      Basically, the end result I want is that I will print a table of the records, which will have as many rows as there are records and 8 columns wide.

      And in order to get a nice, readable table printout I'd use this:
      printf "%-10", $elementToPrint;
      I'm sure you know that this will make a "cell" in the table 10 spaces wide and left justified.
      And what I did in another program I wrote was replace "10" with $colLens[$x], where $x is the largest length of the string in each element for every record, including the @header elements as well.


      So for an example, if I have the following data: (I removed a couple of the column elements so it fits on the page correctly)
      The end result should be that @colLens = (9, 14, 7, 8, 3, 7, 8)
      #Max Column length in parenthesis. (9) (14) (7) (8) (3) (7) (8) OWNER | 999?SheetMusic |ralph |50054441 |156 |pts/220 |9:00:44 WAITING-0 | 999?SheetMusic |randall |33096504 |35 |none |9:10:44 WAITING-1 | 999?SheetMusic |kelly |55555556 |999 |pts/900 |9:00:00 OWNER | 001!SCHEDULE |joe |51515154 |000 |tty/100 |10:00:00 WAITING-0 | 001!SCHEDULE |mvick |12345677 |886 |none |9:20:00 WAITING-1 | 001!SCHEDULE |russel |76543215 |456 |tty/101 |10:00:00


      Sorry if I confused you more, trying my best to explain it as well as I can haha.
      Let me know if you think of anything.


      Thanks Again,
      Matt


      .

      Hey hbm,

      Ok... So I think I figuerd it out.

      Instead of this --> length($rec3) I tried using this --> length($records{ $rec1 }{ $rec2 }{ $rec3 })
      And it seems like its working now!

      I took me a little bit but finally realized that, length($rec3), was giving me the length of the key and not the value.


      Thanks,
      Matt


      .