Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them, it only takes a minute:

I am a first timer with Perl and I have to make changes to a Perl script and I have come across the following:

my %summary ;
for my $id ( keys %trades ) {
    my ( $sym, $isin, $side, $type, $usrOrdrNum, $qty ) = @{$trades{$id}} ;
    $type = "$side $type" ;
    $summary{$sym}{$type} += $qty ;
    $summary{$sym}{'ISIN'} = $isin  ;
}

The portion I do not understand is $summary{$sym}{$type} += $qty ;. What is the original author trying to do here?

share|improve this question
    
$summary{$sym}{$type} is the same as $summary{$sym}->{$type} – doubleDown Jun 13 '13 at 14:14
    
Maybe it gets more clear when you do a print %summary; before and after the line with the +=. – ott-- Jun 13 '13 at 14:16
1  
@ott-- not helpful, that would give sym1ARRAY(0xC0FFEE123)sym2ARRAY(0xDEADBEEF) etc. Better use Data::Dumper; ...; print Dumper \%summary or use Data::Dump; ...; dd \%summary to view nested data structures. – amon Jun 13 '13 at 14:19
    
What perl do you use? perl -e '%coins = ("Quarter", 25, "Dime", 10, "Nickel", 5); print %coins;' gives Nickel5Dime10Quarter25. – ott-- Jun 13 '13 at 14:31
1  
@ott--, the OP has a nested hash. – doubleDown Jun 13 '13 at 14:32

6 Answers 6

up vote 3 down vote accepted

This piece of code populates the %summary hash with a summary of the data in %trades. Each trade is an array with multiple fields which are unpacked inside the loop. I.e. $sym is the value of the first array field of the current trade, $qty the last field

$summary{$sym} accesses the $sym field in the %summary hash. The entry named $type in the $summary{$sym} field is then accessed. If the field does not exist, it is created. If $summary{$sym} does not hold a hashref, one is created there, so everything Just Works. (technical term: autovivification)

$var += $x adds $x to $var, so $summary{$sym}{$type} holds a sum of all $qty values with the same $sym and $type after the loop finishes.

The $summary{$sym}{ISIN} field will hold the $isin value of the last trade with name $sym (I suspect they are the same for all such trades).

share|improve this answer

Perl has three built in different data types:

  • Scalar (as in $foo).
  • Arrays (as in @foo).
  • Hashes (as in %foo).

The problem is that each of these deal with single bits of data. Sure, there can be lots of items in list and hashes, but they are lots of single bits of data.

Let's say I want to keep track of people. People have a first name, last name, phone, etc. Let's define a person:

my %person;

$person{FIRST_NAME} = "Bob";
$person{LAST_NAME} = "Smith";
$person{PHONE_NUMBER} = "555-1234";

Okay, now I need to store another person. Do I create another hash? What if I could have, say an array of hashes with each hash representing a single person?

Perl allows you to do this by making a reference to the hash:

my @list;
push @list, \%person;

THe \%person is my reference to the memory location that contains my hash. $list[0] points to that memory location and allows me to access that person through dereferencing.

Now, my array contains my person. I can create a second one:

$person{FIRST_NAME} = "Susan";
$person{LAST_NAME} = "Brown";
$person{PHONE_NUMBER} = "555-9876";
push @list, \%person.

Okay, how do I reference my person. In Perl, you dereference by putting the correct sigil in front of your reference. For example:

my $person_ref = @list[0];  #Reference to Bob's hash
my %person = %{person_ref}; #Dereference to Bob's hash. %person is now Bob.

Several things, I'm doing a lot of moving data from one variable to another, and I am not really using those variables. Let's eliminate the variables, or at least their names:

my @list;
push @list, {};   #Anonymous hash in my list

$list[0] still points to a reference to a hash, but I never had to give that hash a name. Now, how do I put Bob's information into it?

If $list[0] is a reference to a hash, I could dereference it by putting %{...} around it!

%person = %{ $list[0] };  #Person is an empty hash, but you get the idea

Let's fill up that hash!

${ $list[0] }{FIRST_NAME} = "Bob";
${ $list[0] }{LAST_NAME} = "Smith";
${ $list[0] }{PHONE_NUMBER} = "555-1234";

That's easy to read...

Fortunately, Perl provides a bit of syntactic sweetener. This is the same:

$list[0]->{FIRST_NAME} = "Bob";
$list[0]->{LAST_NAME} = "Smith";
$list[0]->{PHONE_NUMBER} = "555-1234";

The -> operator points to the dereference you're doing.

Also, in certain circumstances, I don't need the {...} curly braces. Think of it like math operations where there's an order of precedence:

(3 x 4) + (5 x 8)

is the same as:

3 x 4 + 5 x 8

One, I specify the order of operation, and the other I don't:

The original adding names into a hash reference stored in a list:

${ $list[0] }{FIRST_NAME} = "Bob";
${ $list[0] }{LAST_NAME} = "Smith";
${ $list[0] }{PHONE_NUMBER} = "555-1234";

Can be rewritten as:

$list[0]{FIRST_NAME} = "Bob";
$list[0]{LAST_NAME} = "Smith";
$list[0]{PHONE_NUMBER} = "555-1234";

(And I didn't have to do push @list, {}; first. I just wanted to emphasize that this was a reference to a hash.

Thus:

$trades{$id}

Is a reference to an array of data.

Think of it as this way:

my @list = qw(a bunch of data);
$trades{$id} = \@list;

And to dereference that reference to a list, I do this:

@{trades{$id}}

See Mark's Short Tutorial About References.

share|improve this answer

$summary{$sym}{$type} is a scalar inside a hashref inside a hash.

+= is an operator that takes the left hand side, adds the right hand side to it, then assigns the result back to the left hand side.

$qty is the value to add to the previously stored value.

share|improve this answer
$summary{$sym}{$type} += $qty ;  #is the same as 
#$summary{$sym}{$type} = $summary{$sym}{$type} + $qty; 
#This line calculates total of the values from the hash %trades ($trades{$id}[5];).
share|improve this answer

The best way to see types in Perl if you are a newbie is to use perl debugger option. You can run the script as :

perl -d <scriptname>

And then withoin the debugger (you will see something like this)

  DB<1>

type the following to go to the code where you want to debug:

  DB<1> c <linenumber>

Then You can use x to see the variables like:

  DB<2>x %trades
  DB<3>x $trades{$id}
  DB<4>print Dumper \%trades

This way you can actually see whats inside the hash or even hash of hash.

share|improve this answer

It computes the sum of all values in the last field for each combination of values of the first three fields.

If the hash was a SQL table instead (and why not - something like DBD::CSV may come in handy here) with fields id, sym, isin, side, type, usrOrdrNum, qty, the code would translate to something like

SELECT sym, CONCAT(side,' ',type) AS type, SUM(qty), isin
FROM trades
GROUP BY sym, CONCAT(side,' ',type);
share|improve this answer
    
To those who downvote this answer: please tell me why. – reinierpost Jun 14 '13 at 10:58
    
Forgot to downvote until now ;-) Your answer provides a translation of the code into a declarative language. However, this requires knowledge of SQL. It introduces the massive DBI framework to do with multiple levels of indirection what OP's simple code can do directly. It ignores that OP has a data structure, not a CSV file. Most importantly, you aren't explaining the code and the syntax, but providing an alternative solution instead. It is conceivable that your answer could have been more confusing than helpful for OP to understand the Perl code he was given. – amon Jun 14 '13 at 12:28
    
The idea of this site is that different answers may be given for the same question. – reinierpost Jun 17 '13 at 17:38

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.