Recurse over a hash without knowing any elements (except top level)

Discussion in 'Perl' started by Christopher, Feb 12, 2004.

  1. Christopher

    Christopher Guest

    I have a hash that is several levels deep.

    ie:

    'vars' => {
    '$filers' => '10.10.10.10/32',
    '$networksa' => '10.10.10.10/32',
    '$networksb' => '10.50.0.0/16',
    '$wintel_boxes' => '10.10.10.10/32',
    },
    'match' => {
    'Rule' => {
    'Doug' => {
    'RuleSub' => {
    'OUTBREAK' => {


    Basically a structure similar in nature to that, basically it could go
    as deep as 8 keys deep with values potentially with each key, but
    usually a value as some level.

    I need to iterate over this and print it out in it's structure, but
    with some formatting. DataDumper does a fine job of doing it in it's
    way, but I cannot customize the pretty output, plus I need to utilize
    the data in other ways.

    So I figure I can load the "top level" keys (say there are 3 of them),
    and then recurse over each subsequent key and gather and print as I
    go.

    Here is what I tried:

    use Config::General;

    my $match_file = qq(match.conf);

    my $match_conf = new Config::General(
    -file => $match_file,
    -AutoTrue => 1);

    my %match_config = $match_conf->getall;

    $depth = 0;

    foreach $key (keys %match_config) {
    print "\t"x$depth;
    print "\n$key\n";
    $depth++;
    &recurse_hash($match_config{$key},$depth);
    }

    sub recurse_hash {

    $match = shift;
    $depth = shift;

    print "\t"x$depth;

    foreach $key2 (keys %{$match}) {
    print "$key2 => $match->{$key2}\n";
    ($match,$depth) = &recurse_hash($match->{$key2},$depth);
    }
    return ($match,$depth);
    }

    I get some results back, but I also get some funk, plus I don't get it
    all, just portions..... I have racked my brain on this, and scoured
    the groups for anykind of similar problem. Most are only 3 levels
    deep, and the levels are known.

    Here is the results:
    Top level keys are typically gonna be (vars, match, and translate):
    vars
    $filers =>
    $networksa =>
    $networksb =>
    $wintel_boxes =>

    match
    Rule => HASH(0x17a918)
    DOUG => HASH(0x17a924)
    RuleSub => HASH(0x17a99c)
    OUTBREAK => HASH(0x17a9a8)
    mail_body => blah blahblah
    mail_cc =>
    page_cc =>
    interval =>
    GUN =>
    DOS =>
    PN =>
    srcnet =>

    translate
    CT2 => HASH(0x183a44)
    27-74 => HASH(0x183abc)
    msg_pattern => HASH(0x183b04)
    ".*filename: => (.*)" = "Bad file: \1"
    27-75 =>
    SN =>
    MSG =>
     
    Christopher, Feb 12, 2004
    #1
    1. Advertising

  2. Christopher

    Guest

    (Christopher) wrote in message news:<>...
    > I have a hash that is several levels deep.
    >
    > ie:
    >
    > 'vars' => {
    > '$filers' => '10.10.10.10/32',
    > '$networksa' => '10.10.10.10/32',
    > '$networksb' => '10.50.0.0/16',
    > '$wintel_boxes' => '10.10.10.10/32',
    > },
    > 'match' => {
    > 'Rule' => {
    > 'Doug' => {
    > 'RuleSub' => {
    > 'OUTBREAK' => {
    >
    >
    > Basically a structure similar in nature to that, basically it could go
    > as deep as 8 keys deep with values potentially with each key, but
    > usually a value as some level.
    >
    > I need to iterate over this and print it out in it's structure, but
    > with some formatting. DataDumper does a fine job of doing it in it's
    > way, but I cannot customize the pretty output, plus I need to utilize
    > the data in other ways.
    >
    > So I figure I can load the "top level" keys (say there are 3 of them),
    > and then recurse over each subsequent key and gather and print as I
    > go.
    >
    > Here is what I tried:
    >
    > use Config::General;
    >
    > my $match_file = qq(match.conf);
    >
    > my $match_conf = new Config::General(
    > -file => $match_file,
    > -AutoTrue => 1);
    >
    > my %match_config = $match_conf->getall;
    >
    > $depth = 0;


    You forgot to declare $depth. "use strict" would have told you about
    this.

    > foreach $key (keys %match_config) {
    > print "\t"x$depth;


    You forgot to declare $key. "use strict" would have told you about
    this.

    > print "\n$key\n";
    > $depth++;
    > &recurse_hash($match_config{$key},$depth);


    Why is that & in there? Do you know what it does? Do you really want
    to do that?

    Assuming $depth is supposed to indicate the depth within the
    structure, it would be more straight-forward to do

    recurse_hash($match_config{$key},1);

    Anyhow it's not clear why you treat the top level specially at all.

    recurse_hash(\%match_config,0);


    > }
    >
    > sub recurse_hash {
    >
    > $match = shift;


    You forgot to declare $match. "use strict" would have told you about
    this. By choosing not to "use strict" you instruct Perl to assume any
    variable you didn't declare is a package variable and thus a global
    variable with respect to the subroutine. Using global variables in
    recursive subroutines is bad.

    > $depth = shift;


    Ouch - you forgot to redeclare $depth within the subroutine. "use
    strict" would not have helped you directly. But the mind-set that
    goes with "use strict" that says "always declare all variables
    lexically scoped in the smallest lexical scope" would have made this
    error much less likely.

    > print "\t"x$depth;


    You probably wanted that on each line - i.e inside the loop.

    > foreach $key2 (keys %{$match}) {


    You forgot to declare $key2. "use strict" would have told you about
    this.

    > print "$key2 => $match->{$key2}\n";
    > ($match,$depth) = &recurse_hash($match->{$key2},$depth);


    You are forgetting to check that $match->{$key2} really is a hash ref
    either before you call &recurse_hash or within that inner subroutine.
    "use strict" would have told you about this because you'd have got an
    error when you tried to use something that wasn't a hash ref as a has
    ref. Without "use strict" Perl will attempt to convert the string
    into a reference by performing a symbol table lookup - this is bad.

    Once again assuming $depth is supposed to indicate the depth within
    the structure, you should be calling recurse_hash with $depth+1.

    > }
    > return ($match,$depth);
    > }


    I do not understand why &recurse_hash needs to return this.

    sub recurse_hash {

    my $match = shift;
    my $depth = shift;

    return unless ref $match eq 'HASH';

    foreach my $key2 (keys %{$match}) {
    print "\t"x$depth, "$key2 => $match->{$key2}\n";
    recurse_hash($match->{$key2},$depth+1);
    }
    }

    > I have racked my brain on this, and scoured
    > the groups for anykind of similar problem.


    The consequences of being careles about your variable scoping and
    choosing not to "use strict" are often discussed (oftem many times per
    day) in the Perl newsgroups that exist. But, of course, you could not
    be expected to realise that those are all "similar problems".

    I would have thought recursive traversal of Perl structures is
    dicussed frequently in the Perl newsgroups that exist. Usually at
    least once a month. But actually, having Googled "recursive reference
    group:comp.lang.perl.*" it does seem much less common than I'd expect.

    Indeed the last thread I could find asking substancially the same
    question as you are asking was the sixth hit I got and was way back in
    August/September.

    That said trawling though six hits isn't all that ownerous. When you
    "scoured
    the groups for anykind of similar problem" what keywords did you try?

    This newsgroup does not (see FAQ). Please do not start threads here.
     
    , Feb 13, 2004
    #2
    1. Advertising

  3. Christopher

    Christopher Guest

    I appreciate your time to go through my code. I admit that I have been
    quite careless, and that I am trying to rectify that habit.

    I search on "recurse hash", and probably did not use have the best use
    of keywords.

    Anway, again thank you for your insight.

    -Chris


    wrote in message news:<>...
    > (Christopher) wrote in message news:<>...

    <snipped>
     
    Christopher, Feb 16, 2004
    #3
    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. John Salerno
    Replies:
    20
    Views:
    858
    John Salerno
    Aug 11, 2006
  2. pabbu
    Replies:
    8
    Views:
    730
    Marc Boyer
    Nov 7, 2005
  3. Fabio Z Tessitore

    who is simpler? try/except/else or try/except

    Fabio Z Tessitore, Aug 12, 2007, in forum: Python
    Replies:
    5
    Views:
    376
  4. rp
    Replies:
    1
    Views:
    537
    red floyd
    Nov 10, 2011
  5. Replies:
    4
    Views:
    188
Loading...

Share This Page