Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Recursively search nested hash/array structures

by mp (Deacon)
on Dec 09, 2004 at 19:16 UTC ( [id://413657]=perlquestion: print w/replies, xml ) Need Help??

mp has asked for the wisdom of the Perl Monks concerning the following question:

I've done a fair amount of searching on google, perlmonks, and cpan for this but have not turned up much, except Data::DRef and Data::Walker. Data::Walker provides a file-system-ish interface command line interfce for manual examination of data structures, but does not provide methods for searching the structures. Data::DRef does not appear to have "search" methods to locate keys recursively, but I will continue look more closely at it.

I have a nested data structure (hash at the top level, then mixture of hashes and arrays at lower levels, arbitrarily deep) that is read from a config file (Config::General).

I need a way to recursively search this data structure for particular hash keys, so that I can alter the data associated with them. For example, certain entries should always have a reference to an anonymous array, so I need to recursively search for a particular key, and wherever found, wrap it's value in an anonymous array if it is not already an array.

So, for example, given:

{ a => { b => 3, } b => 123, c => { b => [ 123, 456, 789, ], }, d => [ b => 456, ], }
I need something that can find all occurrences of 'b' in this data structure, so that I can examine them and change them all to array references like this:
{ a => { b => [ 3, ] } b => [ 123, ], c => { b => [ 123, 456, 789, ], }, d => [ b => [ 456, ], ], }

Similar functionality to what I need exists in File::Find, File::Find::Rule, HTML::TreeBuilder (especially it's look_down method), but these all target either filesystem or file traversal rather than perl data structure traversal.

In the interest of avoiding reinventing a wheel that I'm sure exists somewhere, but I've been unable to find, has anyone found a CPAN module to do this sort of thing?

Replies are listed 'Best First'.
Re: Recursively search nested hash/array structures
by Joost (Canon) on Dec 09, 2004 at 19:37 UTC
      Thank you. Data::Rmap was exactly what I needed. The example script below converts every value corresponding to a key of 'b' to an array unless it already is an array.
      use strict; use warnings; use Data::Rmap qw(rmap_hash); use Data::Dumper; $Data::Dumper::Sortkeys = 1; $Data::Dumper::Indent = 1; my $data = { a => { b => 1, x => 3, }, b => 1, c => { d => [ { b => 3 }, { b => [5, 6, 7] }, { x => 3}, ], }, }; my $key = 'b'; my @to_fix = rmap_hash { exists($_->{$key}) && (ref($_->{$key}) ne "ARRAY") ? $_ : () } $data; for my $h(@to_fix) { $h->{$key} = [ $h->{$key} ]; } warn Dumper($data);
      Output:
      $VAR1 = { 'a' => { 'b' => [ 1 ], 'x' => 3 }, 'b' => [ 1 ], 'c' => { 'd' => [ { 'b' => [ 3 ] }, { 'b' => [ 5, 6, 7 ] }, { 'x' => 3 } ] } };
Re: Recursively search nested hash/array structures
by simonm (Vicar) on Dec 09, 2004 at 19:24 UTC
      Thanks for the quick response. Since you are the author of Data::DRef, I'll take your response to also mean that Data::Dref doesn't have anything that will do this. Initially I had thought that its 'index_by_drefs' sub might allow locating the keys easily, but after some experimentation with it, I can't get it to do that.

      The code you referenced in Clone::PP looks relatively straightforward, so I will start there, if no other leads turn up.

Re: Recursively search nested hash/array structures
by Roy Johnson (Monsignor) on Dec 09, 2004 at 19:40 UTC
    Seems like a Data::Find module would be a nifty parallel to File::Find. But have you seen Data::Search? It looks like it might be able to do what you want.

    Caution: Contents may have been coded under pressure.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://413657]
Approved by Joost
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-04-19 22:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found