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

Hey friends,

I am struggling with a problem. I have a hash, example:

 $myHash{$customer}{money}

The $customer is a value that I get by analizing a database everyday. This means, that everytime I run the script, there might be a new customer. The result of the hash is a scalar (money they spent).

I want to write a procedure how to extract the money they spent, by each $customer. I tried somehow like this:

foreach $customer (keys %myHash){ $money_spent = $myHash{$customer}{money}; }

Ofcourse, I am aware this doesnt work as i want, because the $money_spent will change everytime another $customer comes.

But I don't know how to get it done efficiently. I DO NOT WANT TO USE IF STATEMENTS HERE, LIKE THIS:

foreach $customer (keys %myHash){ print "$customer \n"; #--check what customers are there if ($customer eq 'NAME-OF-CUST'){ $money_spent_name_of_cust = $myHash{$customer}{money}; } ... }

I dont want to manually write down an IF statement for every $customer. There has to be a way, to store the values for each customer into a variable $money_spent.

Ideas very appreciated. David

Replies are listed 'Best First'.
Re: Keys and Values from Hash
by AppleFritter (Vicar) on Jul 18, 2014 at 12:48 UTC

    There has to be a way, to store the values for each customer into a variable $money_spent.

    Do you want to store the value for each customer, or an aggregate? If the former, use a hash;

    my %money_spent = (); foreach my $customer (keys %myHash) { $money_spent{$customer} = $myHash{$customer}->{"money"}; }

    If the latter, simply sum the values:

    my $money_spent = 0; foreach my $customer (keys %myHash) { $money_spent += $myHash{$customer}->{"money"}; }

    You can also use map to do this in a more concise fashion. Per-customer hash:

    my %money_spent = map { $_ => $myHash{$_}->{"money"} } keys %myHash;

    Aggregate (using the sum function from List::Util):

    use List::Util qw/sum/; # ... my $money_spent = sum map { $myHash{$_}->{"money"} } keys %myHash;

    Or do you want to do something else entirely?

    EDIT: note that the above snippets assume that %myHash looks something like this:

    my %myHash = ( "Fred Flintstone" => { "money" => 1000, "wife" => "Wilma", }, "Barney Rubble" => { "money" => 2000, "wife" => "Betty", }, );
      I apologize, I was probably unclear. I will try to explain it better:

      My goals is to get the appropriate value for it's appropriate key in Hash. For example.

      'CUSTOMER1' = 20; 'CUSTOMER2' = 40; 'CUSTOMER3' = 60;

      The above keys and values are in %myHash.

      Now I want to extract each of the value and store it in appropriate Variable. For example:

      $money_spent_customer1 = 20; $money_spent_customer2 = 40;

      The problem is, I only find the solution with knowing what are my $customer and typing an IF statement, to check if the current $customer matcher CUSTOMER1 (for example), etc.

      I was hopping if there is a better way to store the values inside variables seperetely for each $customer

      The end goal of all this is to draw a chart on my HTML page. To see, how much money did certain customer spend. And I want to be automated as possible - so that I tomorow we'll have new customers, I want PERL to generate my HTML without my manual interfering (apart of running the Script).

        So, if I understand correctly, for each customer -- that is to say, each key of %myHash -- you want a variable named after that customer?

        You could do that with soft references (note that this will fail to compile under use strict, and generate warnings even without it):

        my %myHash = ( "FredFlintstone" => 1000, "BarneyRubble" => 2000, ); foreach (keys %myHash) { $var = "money_spent_$_"; $$var = $myHash{$_}; } say $money_spent_FredFlintstone; # 1000 say $money_spent_BarneyRubble; # 2000

        But I'd strongly advise against this. This is precisely the sort of thing that hashes are for.

Re: Keys and Values from Hash
by roboticus (Chancellor) on Jul 18, 2014 at 17:38 UTC

    David92:

    Reading the thread, I think that trying to unwrap the hash into a set of named variables is a mistake. I think that what you really need is something more like:

    my @interesting_customers = get_interesting_customer_list(); my @time_periods = (qw( money3am money6am ... )); # Build a total for customer list foreach $customer (@interesting_customers) { # only looking at the interesting ones $myHash{$customer}{money_spent}=0; foreach $time_period (@time_periods) { $myHash{$customer}{money_spent} += $myHash{$customer}{$time_pe +riod}{money}; } } # How much did 'JoeBiden' spend with us? print "JoeBiden spent $myHash{JoeBiden}{money_spent} dollars with us\n +";

    Once you summarize your data into the hash, you can just use the values as if they were named variables, but you don't need to write explicit code for each customer number.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Keys and Values from Hash
by Laurent_R (Canon) on Jul 18, 2014 at 17:53 UTC
    To have what you want (i.e. one amount for each customer), the bottom line is to use a hash. Since you already have a hash, we could say that you are done... unless your current hash is too complicated for what you want to do. In this case, you need to make a second less complex hash, for example using the code provided earlier by AppleFritter. At the end you would get a simple hash looking like this:
    0 HASH(0x6005e8d88) 'cust1' => 10 'cust2' => 20 'cust3' => 30
    I must say that I am not quite sure to understand what your current data structure really is (and will therefore not supply additional code right now), it would be good if you could explain further (perhaps using the output produced by Data::Dumper on your root hash).