1

I hope I've stated that subject correctly. I have a hash of hashes that I've built from reading a file. The outer hash is groups, then the inner hash is parameters within that group. Each parameter value can either be a scalar or array, and the arrays can start at either zero or one.

I've written a subroutine that returns the value of a parameter. The calling function has to figure out whether the returned value is a scalar or an array. Works fine for scalars. Returns a reference to an array for array values (looks like ARRAY(0x004f00)). Using Data::Dumper spits out data that looks like an array, but I can't figure out how to dereference it in the code. Can someone point to what I'm doing wrong?

%HoH = (
    flintstones => {
        husband     => "fred",
        possessions => [ undef, "car", "record player", "rock" ],
        pal         => "barney",
        pets        => [ "bird", "dinosaur" ],
    },
);

get_value("possessions");

sub get_value {

    my $what_i_want = shift;

    @groups = keys(%HoH);

    foreach my $group ( @groups ) {

        foreach my $param ( keys( %{ HoH {group} } ) ) {

            if ( $param eq $what_i_want ) {
                return $HoH{$group}{$param};
            }
        }
    }
}

The caller assigns the return value to an array, @return, so in the case of a scalar it should put the value in $return[0].

In the case of an array, it should populate the array. When I call Dumper, it prints out scalars in single quotes and arrays in square brackets, as it should. However, when I use scalar(@return) to check the size of the array, it returns 1.

I've tried dereferencing the return statement using square brackets at the end to see if I could even get a scalar returned, but no luck.

Borodin
  • 126,100
  • 9
  • 70
  • 144
Andy
  • 11
  • 3

1 Answers1

2

You don't show the subroutine being called in context, but a quick fix would be to put this after the call

@return = @{ $return[0] } if ref $return[0]



Update

You're missing the point of hashes. You can access the correct element of the parameter hash by using $what_i_want as a hash key

I suggest you change your subroutine code to look like this

for my $group ( keys %HoH ) {

    my $ret = $HoH{$group}{$what_i_want};

    return unless defined $ret;
    return ref $ret ? @$ret : $ret;
}

That way it will never return a reference



Update 2

Here's your complete program modified as I suggested

use strict;
use warnings 'all';

my %HoH = (
    flintstones => {
        husband     => "fred",
        possessions => [ undef, "car", "record player", "rock" ],
        pal         => "barney",
        pets        => [ "bird", "dinosaur" ],
    },
);

my @return = get_value('possessions');

use Data::Dump;
dd \@return;

sub get_value {

    my ($wanted) = @_;

    for my $group ( keys %HoH ) {

        my $ret = $HoH{$group}{$wanted};

        if ( defined $ret ) {
            return ref $ret ? @$ret : $ret;
        }
    }

    return;
}

output

[undef, "car", "record player", "rock"]
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • I can't copy over code direct, so I had to retype it. Added a little context, modified from the camel book examples. I agree that your method would be easier, but the value doesn't know the group that it belongs to (e.g. Fred doesn't know he's on the Flintstones). Edit: I see what you did... too Perlish to be intuitively obvious. Will try it. Thanks! – Andy Jan 20 '16 at 01:53
  • *"I can't copy over code direct"* Don't you have a web browser on the same system as your Perl development? *"the value doesn't know the group that it belongs to"* You're misunderstanding. You still have to loop over the groups, but you can use `$what_i_want` directly as a key to the parameter hashes – Borodin Jan 20 '16 at 02:01
  • No, my development machine is on an isolated network. I see where you looped over the groups, and I do understand about hashes. My perl is quite rusty (~10 years), and my book is quite dusty (2000), so forgive that oversight. So I learn something from this, the biggest difference I see aside from style and the deletion of the inner loop is the `return` statement. I'll have a look at it tomorrow to try to understand what you did and why it works. But it does work, and for that I thank you. – Andy Jan 20 '16 at 02:23
  • The core of the solution is `ref $ret ? @$ret : $ret`, which dereferences `$ret` as an array if it is a reference, otherwise leaves it alone – Borodin Jan 20 '16 at 02:27