Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Nice :).

First:

my $out .= "var "; my $out .= "var ";
What what? And please don't name your hashrefs $array ;-).

Just so we're clear. Your idea will work when the keys identify uniquely the associated values, so something like this would be valid perl, but invalid input:

(Shapes => [ { Type => 'Circle', Diameter => 2, Center => [0,1] }, { Type => 'Square', Side => 3, Pos => [4,8] }, [ {x => 1, y => 1}, {x => 3, y => 1}, {x => 4, y => 2}, {x => 2, y + => 2} ] ] );
The values in the Shapes array can either be hashes describing the shape, or an array of points, and you need to look inside the hashes to know the type of shape and the associated members.
Edit: actually my solution below accepts mixed ARRAY/HASH. It just melds Circle and Square together in a way that might not make much sense.

As can be seen, my crude approach of merging each element into a %giant_hash, while great for data if everything within the array hashes is a hash, falls down when arrays are encountered.
Actually the hash is the issue, in %giant_hash = (%giant_hash, %$array); if there are keys in %$array that are already present in %giant_hash, they will overwrite them. This means that the kids of Marge Keefe will erase the kids of Tony Jones.

A hash in perl can only hold a single value (scalar) for each key. That value can be a reference that holds other values, but perl won't just do that on its own when you "merge" hashes, so in %giant_hash, you will only have the fname, last_name, occupation and set of kids. So you can't actually merge the hash that way before iterating over it.

The reason you merged the hashes in the first place is that they are of the same type, so contain similar data. That's also true for the kids (basically they have a name, an age, and might be vaccinated), so you should "merge" them, and show that "kids" may contrary may contain an arbitrary number of elements of type "kid". Which would make your output look like:

var is a HASH with 5 keys the keys are 'age', 'fname', 'kids', 'last_name', 'occupation' key 'kids' is an ARRAY containing HASHREFs: the keys are 'age', 'name', 'vaccinated' key 'vaccinated' is a SCALAR key 'age' is a SCALAR key 'name' is a SCALAR key 'fname' is a SCALAR key 'age' is a SCALAR key 'occupation' is a HASH with 2 keys the keys are 'title', 'years_on_job' key 'title' is a SCALAR key 'years_on_job' is a SCALAR key 'last_name' is a SCALAR

Here is my attempt at solving your problem. There are of course many ways to do it, keeping the list of keys down to the current point rather than a reference to the current level might be a better way to work (you don't have to provide the output hash as a parameter), but I just went where my fingers took me :D

use v5.14; use strict; use warnings; use Data::Dump qw( pp ); use YAML; sub introspect { my ($data, $output) = @_; if (ref $data eq 'ARRAY') { my $sub_out = ($output->{'ARRAY'} //= {}); introspect($_, $sub_out) for @{ $data }; } elsif (ref $data eq 'HASH') { my $hash_out = $output->{"HASH"} //= {}; for my $key (keys %$data) { my $sub_out = ($hash_out->{"$key"} //= {}); introspect($_, $sub_out) for $data->{$key}; } } elsif (ref $data) { $output->{ref($data).'REF'}=1; } else { $output->{SCALAR}=1; } } my @array = ({fname => 'bob', last_name => 'smith', foo => [\*main]}, {fname => 'tony', last_name => 'jones', age => 23, kids => [ {first_name => 'cheryl', middle_name => 'karen', age => 24 }, {name => 'jimmy', age => 17 } ], }, {fname => 'janet', last_name => 'marcos', foo => {}, occupation => { title => 'trucker', years_on_job => 12} }, {fname => 'Marge', last_name => 'Keefe', kids => [ {name => 'kate', age => 7, vaccinated => 'yes'}, {name => 'kim', age => 5} ] }); my %out; introspect(\@array, \%out); say pp \%out; say YAML::Dump(\%out);
{ ARRAY => { HASH => { age => { SCALAR => 1 }, fname => { SCALAR => 1 }, foo => { ARRAY => { GLOBREF => 1 }, HASH => {} }, kids => { ARRAY => { HASH => { age => { SCALAR => 1 }, first_name => { SCALAR => 1 }, middle_name => { SCALAR => 1 }, name => { SCALAR => 1 }, vaccinated => { SCALAR => 1 }, }, }, }, last_name => { SCALAR => 1 }, occupation => { HASH => { title => { SCALAR => 1 }, years_on_job => { SCALAR = +> 1 } }, }, }, }, } --- ARRAY: HASH: age: SCALAR: 1 fname: SCALAR: 1 foo: ARRAY: GLOBREF: 1 HASH: {} kids: ARRAY: HASH: age: SCALAR: 1 first_name: SCALAR: 1 middle_name: SCALAR: 1 name: SCALAR: 1 vaccinated: SCALAR: 1 last_name: SCALAR: 1 occupation: HASH: title: SCALAR: 1 years_on_job: SCALAR: 1

Edit: you can add this case to handle things like \\\\\{};

elsif (ref $data eq 'REF') { introspect($$data, ($output->{'REF'} //= {})); }


In reply to Re: How to improve introspection of an array of hashes by Eily
in thread How to improve introspection of an array of hashes by nysus

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2024-04-25 14:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found