Thursday, February 4, 2010

Hashes are fun

Another day gone and another fun day of Mason and Perl learning.

I should preface this by saying as I am still learning there most likely WILL be errors. Please comment and correct me. I'll gladly edit the post to correct. I am still learning here. :)

#1 Gripe, dealing with Hashes.

Don't get me wrong, I love 'em, and they are incredibly handy, but I spent a good part of the day figuring out multi-dimensional hashes, declaring them and using them. When all is said and done I forgot about how hashes are stored how Perl wants to store them, for better efficiency. Whenever you alter it, it could be in a different order. Oh well. Multi-dimensional arrays that emulate hashes, GO!

Hashes and arrays, as compared to PHP

PHP:

$var = array();
//Empty Array

$var = array(12,23,2);
// Normal Array, each item in their ordered position
// $var[0] == 12, $var[1] == 23, $var[2] == 2

$var = array('coke' => 'soda' , 'paper' => 'wood');
// Associative Array (this is like a hash in perl)

$var = array(
'Dinner' => array(
'steak' ,
'veggies',
'wine'
)
);
//This is a multi-dimensional array and can be used simply by calling the values
//$var['Dinner'][0] == 'steak';

END PHP

<%perl>

# Some background about variables in Perl
# $var - scalar (single variable)
# @var - list (an array)
# %var - hash (an associative array)

$variable = 'ice cream';
@variable = ('breakfast','lunch','dinner');
%variable = { 'breakfast' => 'cereal', 'dinner' => 'Cheese Steak' };

Correction (ty cole)
The '%' sigil represents a symbol that *is* a hash. When you create a hash using curly braces, you're returning a reference *to* a hash. So if you do the assignment you talked here, it doesn't work the way you want.

#So in other words, my free use of { } was wrong. Here is the proper definition of that datatype that actually will return the hash and not the reference to the has.

%variable = ( 'breakfast' => 'cereal', 'dinner' => 'Cheese Steak' );

<%/perl>

You will notice the difference in ( vs. { when you're using an array vs. a hash. For added fun, if you want to reference anything you want to treat it like a scalar. It assumes you want to return a scalar when you reference a hash.

In this case: %variable = { 'breakfast' => 'cereal', 'dinner' => 'Cheese Steak' };

print $variable{'dinner'} will return the scalar 'Cheese Steak' so perl has done right. (note the { brackets again)

Dereferencing
When you read from a hash remember, Perl assumes it's a scaler, to tell it to be something else you need to apply the appropriate prefix.

If %variable had been
%variable = {
'dinner' => {
'Cheese Steak',
'Chips',
'Soda'
}
}

$variable{'dinner'} will still return a scalar but now it'll be the pointer to the sub-hash.

To get to the hash I need to tell perl that what it is returning needs to be another hash which means wrapping it in the hash indicator %{}.

%new_hash = %{$variable{'dinner'}}; #congrats, we now have our sub-hash to read.

Fun stuff. I love that I'm learning!

3 comments:

Unknown said...

Close dude. I know perl isn't the simplest language to figure out wrt sigils. There's a bit of a bug in your post as it stands though.

The '%' sigil represents a symbol that *is* a hash. When you create a hash using curly braces, you're returning a reference *to* a hash. So if you do the assignment you talked here, it doesn't work the way you want. Try this to see what I mean:

perl -e 'use Data::Dumper; $Data::Dumper::Indent = 1; %a = {"a" => 1, "b" => 2}; print Dumper(\%a), "\n";'

What you really wanted to do is to do something like %a = ("a" => 1, "b" => 2); In other words, you want parens around the hash definition rather than curly braces.

Don't worry - you'll get there.

Unknown said...

One other comment. The line:

%new_hash = %{$variable{'dinner'}};

will cause that sub hash to be copied. In this scenario, you are probably better off (unless you have a good reason to get a copy) to get a reference to it, which is syntactically easier.

$hash_ref = $variable{'dinner'}

$variable{'dinner'} is a scalar. And in this case, that scalar is a reference to a hash. Now you can grab items out of that sub hash one of two ways.

Let's say that $hash_ref looks like:

{'a' => 1, 'b' => 2}

You could then use either of the following syntaxes to grab an element out:

print "A: " . $hash_ref->{'a'} . "\n";
print "B: " . $$hash_ref{'b'} . "\n";

Alex Lessard said...

Awesome, tyvm Cole!