Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Looping through multi dimensional hash 1

Status
Not open for further replies.

whn

Programmer
Oct 14, 2007
265
US
A sample hash would be like this:
Code:
my %hash = (
  'key1'=>'val1',
  'key2'=>{
    'key21'=>'val21',
    'key22'=>'val22',
    'key23'=>{
      'key231'=>'val231',
      'key231'=>'val232',
    },
    'key24'=>'val24',
  },
  'key3'=>'val3',
);
We don't know how many levels each dimension goes, how to loop through it?

I guess recursive call could be the answer. But I don't know how to implement it exactly.

Could someone show me a sample code?

Many thanks.
 
That was an interesting exercise for me, thanks!

Not sure this is the best way, I'd welcome comments, particularly if the hash referencing could/should be simplified?

Code:
[gray]#!/usr/bin/perl -w[/gray]
[url=http://perldoc.perl.org/functions/use.html][black][b]use[/b][/black][/url] [green]strict[/green][red];[/red]

[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]%hash[/blue] = [red]([/red]
  [red]'[/red][purple]key1[/purple][red]'[/red]=>[red]'[/red][purple]val1[/purple][red]'[/red],
  [red]'[/red][purple]key2[/purple][red]'[/red]=>[red]{[/red]
    [red]'[/red][purple]key21[/purple][red]'[/red]=>[red]'[/red][purple]val21[/purple][red]'[/red],
    [red]'[/red][purple]key22[/purple][red]'[/red]=>[red]'[/red][purple]val22[/purple][red]'[/red],
    [red]'[/red][purple]key23[/purple][red]'[/red]=>[red]{[/red]
      [red]'[/red][purple]key231[/purple][red]'[/red]=>[red]'[/red][purple]val231[/purple][red]'[/red],
      [red]'[/red][purple]key232[/purple][red]'[/red]=>[red]'[/red][purple]val232[/purple][red]'[/red],
    [red]}[/red],
    [red]'[/red][purple]key24[/purple][red]'[/red]=>[red]'[/red][purple]val24[/purple][red]'[/red],
  [red]}[/red],
  [red]'[/red][purple]key3[/purple][red]'[/red]=>[red]'[/red][purple]val3[/purple][red]'[/red],
[red])[/red][red];[/red]

[url=http://perldoc.perl.org/functions/sub.html][black][b]sub[/b][/black][/url] [maroon]printhash[/maroon] [red]{[/red]
        [black][b]my[/b][/black] [blue]%hash[/blue]=[blue]@_[/blue][red];[/red]
        [olive][b]foreach[/b][/olive] [red]([/red][url=http://perldoc.perl.org/functions/sort.html][black][b]sort[/b][/black][/url] [url=http://perldoc.perl.org/functions/keys.html][black][b]keys[/b][/black][/url] [blue]%hash[/blue][red])[/red] [red]{[/red]
                [olive][b]if[/b][/olive] [red]([/red][url=http://perldoc.perl.org/functions/ref.html][black][b]ref[/b][/black][/url] [blue]$hash[/blue][red]{[/red][blue]$_[/blue][red]}[/red][red])[/red] [red]{[/red]
                        [maroon]&printhash[/maroon][red]([/red][blue]%[/blue][red]{[/red][blue]$hash[/blue][red]{[/red][blue]$_[/blue][red]}[/red][red]}[/red][red])[/red][red];[/red]
                [red]}[/red] [olive][b]else[/b][/olive] [red]{[/red]
                        [url=http://perldoc.perl.org/functions/print.html][black][b]print[/b][/black][/url] [red]"[/red][purple][blue]$_[/blue] => [blue]$hash[/blue]{[blue]$_[/blue]}[purple][b]\n[/b][/purple][/purple][red]"[/red][red];[/red]
                [red]}[/red]
        [red]}[/red]
[red]}[/red]

[maroon]&printhash[/maroon][red]([/red][blue]%hash[/blue][red])[/red][red];[/red]

Annihilannic.
 
Annihilannic,
it is more efficient to make use of references, instead of passing entire arrays or hashes to a routine (especially if it's a recursive one)
Code:
use strict;
my%hash=(
  'key1'=>'val1',
  'key2'=>{
    'key21'=>'val21',
    'key22'=>'val22',
    'key23'=>{
      'key231'=>'val231',
      'key232'=>'val232',
    },
    'key24'=>'val24',
  },
  'key3'=>'val3',
);
sub printhash {
  my($refhash)=@_;
  foreach(sort keys%$refhash){
    if(ref $$refhash{$_}){
      &printhash($$refhash{$_});
    }else{
      print"$_ => $$refhash{$_}\n";
    }
  }
}
&printhash(\%hash);

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Thank you both, Annihilannic & prex!!

The solution you provided only prints the keys at the lowest level. Coud it be enhanced so that it can print all keys at different level, e.g. something like:

$refhash->{key2}->{key23}->{key231} = val231

?

Thanks for the help.

 
Just modify as follows:
Code:
sub printhash {
  my($refhash,$keysofar)=@_;
  for(sort keys%$refhash){
    if(ref$$refhash{$_}){
      printhash($$refhash{$_},$keysofar.$_.' => ');
    }else{
      print$keysofar,$_,' => ',$$refhash{$_},"\n";
    }
  }
}

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Thank you, prex!!

This version works very well!!

 
Under nested Key=>23 there are duplicate keys - if this is the actual data, only ONE value will be reported back.

Code:
'key23'=>{
      'key231'=>'val231',
      'key231'=>'val232',
    },
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top