http://qs1969.pair.com?node_id=431432

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

I have a data structure returned by Frontier::Client that "print Dumper($result)" shows as:
$VAR1 = [ { 'state' => 'CA', 'suffix' => '', 'lat' => '37.783941', 'city' => 'San Francisco', 'number' => '833', 'zip' => '94103', 'long' => '-122.404900', 'prefix' => '', 'type' => 'St', 'street' => 'Mission' } ];
print $result->{'city'} gives error Argument "San Francisco" isn't numeric in hash element. which I don't understand. How do I get at this data? All I can do right now is list the keys:
foreach my $key ( sort keys %{$result} ) { print "$key\n"; }

Replies are listed 'Best First'.
Re: Frontier::Client mystery result string hash
by ikegami (Patriarch) on Feb 16, 2005 at 04:52 UTC

    Notice the square brackets around the curly ones. You have a reference to an array, not a reference to hash. The first (and only) element of the array is a reference to a hash, so:

    print($result->[0]{'city'}, "\n");

    or

    foreach $record (@$result) { foreach $field (keys %$record) { printf("%s: %s\n", $field, $record->{$field}, ); } print("\n"); }
      Yup, you got it. I had been unable to create a matching data structure prior to your hint. This works:
      print "Print city: $result->[0]{'city'}\n";
      But I decided the following looked "cleaner". It makes me cringe, but here it is:
      my %hash = %{$result->[0]}; # copy result to new hash ... print "Print city: $hash{'city'}\n";
      I still can't quite figure out why Frontier::Client put this result in such a pointlessly nested data structure...
        Why would this be cleaner? You've got a reference to an array, containing a hash, meaning it only exists 1 time in your memory.
        Now you're dereferencing it into another hash, resulting in being twice in the memory. Do this with larger hashes over and over, and the memory usage becomes bigger and bigger.
        Print city: $result->[0]{'city'}\n"; is a verry legitimate way to write the results, i'd like the iterative way even more, in $result->[1] may be another hash, so i'd use ikegami's approach:
        foreach $record ( @{$result} ) { foreach $field (keys %$record) { printf("%s: %s\n", $field, $record->{$field}, ); } print("\n"); }

        This doesn't create a copy, just an alias:

        local %hash; *hash = $result->[0]; ... print "Print city: $hash{'city'}\n";
        I still can't quite figure out why Frontier::Client put this result in such a pointlessly nested data structure...

        Could it possibly return more than one result? Or maybe it's just extending a generic module that returns the data in that fashion.

        I still can't quite figure out why Frontier::Client put this result in such a pointlessly nested data structure...

        Because it's not pointless. The XML-RPC protocol allows for arrays of hashes. This means that the outer array is useful. It's just not useful in your situation.

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Frontier::Client mystery result string hash
by Tanktalus (Canon) on Feb 16, 2005 at 04:54 UTC

    That doesn't look quite right. First off, are you doing:

    print Dumper($result)
    or
    print Dumper([$result])
    ? If you're doing the former, that means $result is an array ref. The array so ref'd has one entry in it: a hash ref. That hash has a bunch of keys, including state, suffix, lat, and city. That is option #1. If you're doing the latter, then $result is a hash ref. This is option #2.

    In option #1, you would find the city via: $result->[0]->{'city'} or, my preference, $result->[0]{'city'} (the quotes are optional in both cases).

    In option #2, you would find the city as you attempted.

    Either way, I'm not sure that your error is coming from the print statement. Can you come up with a minimal working script that shows your problem? You can skip Frontier::Client, if the problem isn't there, by setting up $result in your minimal script.

    Thanks

      Thanks. I did indeed use the plain print Dumper($result) as I had specified.
Re: Frontier::Client mystery result string hash
by jbrugger (Parson) on Feb 16, 2005 at 05:22 UTC

    Ah, both ikegami and Tanktalus posted ad the same time... Same answer and both correct :-)

    However, if you want to ban out the use of Dumper to sort out the type of your variable, you'd also could use:

     print (ref($result));

    to check the type.