...

View Full Version : how to extend length of hash -tute plz



bazz
08-18-2009, 05:39 AM
Hi,

I have a hash with three values and because I have got newly entered data I want to add to that hash. I don't mean build the hash but extend it.

like this

$stuff{$product_id}{$product_name}{$price};
is to become this

$stuff{$product_id}{$product_name}{$price}{$year_of_manufacture};

So I have my hash:- %stuff but I can't seem to find how to add more columns/fileds to it.

Any pointers or tutorials very welcome.

I think I should just build a new hash but I wonder if there is an already better way.

bazz

hackYourBrain
08-18-2009, 04:28 PM
$stuff{$product_id}=$product_name;





for($i=0;$product_id;$i++){
$stuff{$product_id[$i]}=$product_name[$i];
}


if you want a three dimensial or more arrays or hashes then u want something like this



@breakfast = ("Cheese","bread","Tuna");
@lunch = ("chicken","rice");
@tea = ("steak","water","fish");

@today = (\@breakfast,\@lunch,\@tea);
push @lunch,"soup";
push @{$today[1]},"salad";

$tea[1] = "hot $tea[1]";
$today[3][0] = "milk";

print $today[2][1],"\n";

foreach $course (@today) {
@this = @$course;
print ".... @this\n";
}


not sure why u asking that.. arent u a senior code??

DoubleThink

FishMonger
08-18-2009, 06:36 PM
Your nesting is to deep. You should use a HoH, not a HoHoHoH.

Example:

use Data::Dumper;

%product = ( 123 => { name => 'product1',
'yr_of_mfg' => 2003,
'price' => 100,
},
231 => { name => 'product2',
'yr_of_mfg' => 2005,
'price' => 200,
},
);

# let's add another product;
$product{321} = { name => 'product3',
'yr_of_mfg' => 2007,
'price' => 400,
};

print Dumper \%product;

Outputs:


$VAR1 = {
'231' => {
'name' => 'product2',
'price' => 200,
'yr_of_mfg' => 2005
},
'123' => {
'name' => 'product1',
'price' => 100,
'yr_of_mfg' => 2003
},
'321' => {
'name' => 'product3',
'price' => 400,
'yr_of_mfg' => 2007
}
};

hackYourBrain
08-19-2009, 03:24 AM
hmm.. interesting.

NewLosAngeles

FishMonger
08-19-2009, 04:34 AM
I left out an example.

Lets say you want to "extend" the hash in my previous example, such as by adding a "manufacturer", here's an example of how to do it.


use Data::Dumper;

%product = ( 123 => { name => 'product1',
'yr_of_mfg' => 2003,
'price' => 100,
},
231 => { name => 'product2',
'yr_of_mfg' => 2005,
'price' => 200,
},
);

# let's add another product;
$product{321} = { name => 'product3',
'yr_of_mfg' => 2007,
'price' => 400,
};

# lets "extend it"
$product{321}{'manufacturer'} = 'company.com';

print Dumper \%product;

Outputs:

$VAR1 = {
'231' => {
'name' => 'product2',
'price' => 200,
'yr_of_mfg' => 2005
},
'123' => {
'name' => 'product1',
'price' => 100,
'yr_of_mfg' => 2003
},
'321' => {
'manufacturer' => 'company.com',
'name' => 'product3',
'price' => 400,
'yr_of_mfg' => 2007
}
};

bazz
08-19-2009, 09:07 AM
As ever FishMonger, that makes sense.

Now it's time for real data variables.

The two methods below build the hash differently. I think the second is the better (only) way. However, I would appreciate your comments because hashes have been a nightmare for me to grasp a hold of.

This was the first way (since your last post).


$new_tariffs_hash{$live_product_id}{'age_data'}{$age_group}{$terms_abbr}{$terms}{$price}++;
$new_tariffs_hash{$live_product_id}{'tariff_start_date'}=$tariff_start_date;
$new_tariffs_hash{$live_product_id}{'tariff_end_date'}=$tariff_end_date;
$new_tariffs_hash{$live_product_id}{'nights_on_first_tariff'} = $nights_on_first_tariff;
$new_tariffs_hash{$live_product_id}{'nights_on_second_tariff'} = $nights_on_second_tariff;



This is my most recent way and it is easier to follow the dumped output and may associate sufficiently well.



$new_tariffs_hash{$live_product_id}{'age_data'}{$age_group}{$terms_abbr}{$terms}=$price;
$new_tariffs_hash{$live_product_id}{'tariff_start_date'}=$tariff_start_date;
$new_tariffs_hash{$live_product_id}{'tariff_end_date'}=$tariff_end_date;
$new_tariffs_hash{$live_product_id}{'nights_on_first_tariff'} = $nights_on_first_tariff;
$new_tariffs_hash{$live_product_id}{'nights_on_second_tariff'} = $nights_on_second_tariff;


This is the dumped output from the second code.



'tariffs_hash' => {
'84' => {
'tariff_end_date' => '2010-03-31',
'tariff_start_date' => '2009-10-01',
'age_data' => {
'Adult' => {
'pppns' => {
'Per Person Per Night Sharing ' => '32.50'
},
'prpn' => {
'Per Room Per Night' => '65.00'
},
'sopn' => {
'Single Occupancy Per Night' => '45.00'
}
}
},
'nights_on_second_tariff' => 0,
'nights_on_first_tariff' => 5
},

'85' => {
'tariff_end_date' => '2009-09-30',
'tariff_start_date' => '2009-08-01',
'age_data' => {
'Adult' => {
'pppns' => {
'Per Person Per night Sharing ' => '32.50'
},
'prpn' => {
'Per Room Per Night' => '65.00'
},
'sopn' => {
'Single Occupancy Per Night' => '45.00'
}
}
},
'nights_on_second_tariff' => 3,
'nights_on_first_tariff' => 2
},
'83'=>{
'tariff_end_date' => '2009-09-30',
'tariff_start_date' => '2009-08-01',
'age_data' => {
'Up to 12 yrs' => {
'pacpn' => {
'Per Accompanied Child Per Night' => '25.44'
}
},
'Adult' => {
'pppns' => {
'Per Person Per Night Sharing ' => '30.00'
},
'prpn' => {
'Per Room Per Night' => '60.00'
},
'sopn' => {
'Single Occupancy Per Night' => '40.00'
}
}
},
'nights_on_second_tariff' => 3,
'nights_on_first_tariff' => 2
}
},


Is the second way how you would do it? I have still a bit of tweaking to do because I need to be able to show more than one start date, to be able to relate the pricing to the date.

(I think I have been doing the usual and making life more difficult. I was trying to use the variables as the category name in the hash and when that wasn't possible, I built it too deeply).

any advice you can give would be most welcome.

bazz

bazz
08-19-2009, 02:13 PM
OK, I have made the hash where the $value is a string of the required, associated data. should be simple enough to split it in the 'while' loop and to use it as required.

bazz

bazz
08-20-2009, 04:05 PM
Hi,

Never mind.. I'm officially stoopid. I got it in the end.

bazz

Jolle
08-21-2009, 03:25 PM
This is my most recent way and it is easier to follow the dumped output and may associate sufficiently well.

Sorry to mingle. Don't know if it's still necessary, but I think you're using the hashes here quite inefficiently. Normally, if you can avoid extra levels, you should. Hashes in Perl are not that time-economic.

I don't really get why you have a level $terms_abbr and a level $terms. I would get rid of the level $terms and create a second hash to link the $terms_abbr and the $terms. The same I'd do for the levels "age_data" and $age_group.

Something like this :


$terms_abbr_hash{$terms_abbr}{$full}=$terms;
$terms_abbr_hash{$terms_abbr}{'age data'}=$age_group;

$new_tariffs_hash{$live_product_id}{$terms_abbr}=$price;
$new_tariffs_hash{$live_product_id}{'tariff_start_date'}=$tariff_start_date;
$new_tariffs_hash{$live_product_id}{'tariff_end_date'}=$tariff_end_date;
$new_tariffs_hash{$live_product_id}{'nights_on_first_tariff'} = $nights_on_first_tariff;
$new_tariffs_hash{$live_product_id}{'nights_on_second_tariff'} = $nights_on_second_tariff;

I think this is a bit more economic on the memory too. If you build your hash as deep as you do, you actually duplicate the same information numerous times : the term-abbreviations are always related to the same age group and the same terms, no?

Hope this makes sense. Feel free to disagree, I'm no expert.

bazz
08-21-2009, 04:14 PM
food for thought, certainly.

I shall mull over your suggestion and try to make the hashes run more efficiently.



the term-abbreviations are always related to the same age group and the same terms, no?


not quite. the terms relate to the price irrespective of the age group. they are effectiently, price clarification. eg pppn = per person per night.

But I get the principle of your post and I'll try to work with it for a better outcome.

Finally; finally, hashes are becoming clearer to me. what is it they say - necessity is the mother of all invention? ;) On further thought maybe it's, 'mother is the inventor of all necessity' :D

bazz

Jolle
08-21-2009, 04:25 PM
food for thought, certainly.
you're welcome. Enjoy the lunch ;)


not quite. the terms relate to the price irrespective of the age group. they are effectiently, price clarification. eg pppn = per person per night.
I see. I just assumed it as you didn't seem to have a term_abbreviation that is used in two age groups.

Good luck with it.

bazz
08-21-2009, 06:11 PM
I'll try the new approach and do some benchmarking to see the efficiency differences.

bazz

Jolle
08-21-2009, 06:24 PM
I'll try the new approach and do some benchmarking to see the efficiency differences.

bazz
On second thought, it might be easier if you adjust a bit, otherwise it gets complicated to extract all prices. Some code to illustrate what I mean :



#!/usr/bin/perl -w
use strict; # yeah, I'm feeling kinky

my (%terms_abbr_hash, %new_tariffs_hash);

# the data
my @terms_abbr_array = (
["pppns", "Per Person Per night Sharing","Adult"],
["prpn", "Per Room Per Night","Adult"],
["sopn", "Single Occupancy Per Night","Adult"],
["pacpn", "Per Accompanied Child Per Night","Up to 12 yrs"]
);

# the loop to fill your hash
foreach (@terms_abbr_array){
my ($terms_abbr,$terms,$age_group)=@{$_}; # unref array, keep local
# fill up the hash
$terms_abbr_hash{$terms_abbr}{full}=$terms;
$terms_abbr_hash{$terms_abbr}{agedata}=$age_group;
}

# let's make some data. first the product specifications
my @new_tariffs_array = (
[84,"2010-03-31","2009-10-01",0,5],
[85,"2009-09-30","2009-08-01",3,2],
[83,"2009-09-30","2009-08-01",3,2]
);
# let's fill the hash
foreach (@new_tariffs_array){
my ($live_product_id,$tariff_start_date,$tariff_end_date,
$nights_on_first_tariff,$nights_on_second_tariff)=@{$_};

$new_tariffs_hash{$live_product_id}{tariff_start_date}=$tariff_start_date;
$new_tariffs_hash{$live_product_id}{tariff_end_date}=$tariff_end_date;
$new_tariffs_hash{$live_product_id}{nights_on_first_tariff} = $nights_on_first_tariff;
$new_tariffs_hash{$live_product_id}{nights_on_second_tariff} = $nights_on_second_tariff;
}
# OK, lets add some prices
my @new_tariffs_prices =(
[84,"pppns",32.50],
[84,"prpn",65.00],
[84,"sopn",45.00],
[85,"pppns",32.50],
[85,"prpn",65.00],
[85,"sopn",45.00],
[83,"pacpn",25.44],
[83,"pppns",30.00],
[83,"prpn",60.00],
[83,"sopn",40.00],

);
# let's fill the hash
foreach (@new_tariffs_prices){
my ($live_product_id,$terms_abbr,$price)=@{$_};
$new_tariffs_hash{$live_product_id}{prices}{$terms_abbr}=$price;
}

# And let's print everything out in a readable format :
foreach my $id (keys %new_tariffs_hash){
print qq/
Product $id :
Tariff start date : $new_tariffs_hash{$id}{tariff_start_date}
Tariff end date : $new_tariffs_hash{$id}{tariff_end_date}
Night on first tariff : $new_tariffs_hash{$id}{nights_on_first_tariff}
Nights on second tariff : $new_tariffs_hash{$id}{nights_on_second_tariff}
Prices :
/;
foreach my $term_abbr (keys %{$new_tariffs_hash{$id}{prices}}){
print qq/
$terms_abbr_hash{$term_abbr}{full} : $new_tariffs_hash{$id}{prices}{$term_abbr}
ageclass : $terms_abbr_hash{$term_abbr}{agedata}
/;
}
}

# Let's try to display all prices for a certain product and a certain age group :
while (1){ # play with an infinite loop a bit
print "\nGive a product or type C to cancel :";
my $prodid = <STDIN>;
chomp $prodid;
print "\nGive an age group : Adult or Minor :"
unless $prodid =~/C/i and last;
my $agegroup = <STDIN>;
if ($agegroup =~ /adult/i){
$agegroup = "Adult";
} elsif ($agegroup =~ /minor/i){
$agegroup = "Up to 12 yrs";
} else {
print "\n Age group is not valid.\n" and next;
}
# let's find what we need
my %prices = %{$new_tariffs_hash{$prodid}{prices}} or
(print "\nProduct not found\n" and next);
foreach (keys %prices) {
print "$terms_abbr_hash{$_}{full} : $prices{$_}\n"
unless ($terms_abbr_hash{$_}{agedata} ne $agegroup) and next;
}
}
That's at least how I would do it. I think in my own thread, there is an example of that in one of the scripts too.

Let me know the results of the benchmarking, I'm quite curious in fact. I'm not an experienced programmer, so I might be way off here.

Jolle
08-21-2009, 06:31 PM
Just to make sure, my last code would create hashes equivalently to :


$terms_abbr_hash{$terms_abbr}{'full'}=$terms;
$terms_abbr_hash{$terms_abbr}{'age data'}=$age_group;

$new_tariffs_hash{$live_product_id}{'prices'}{$terms_abbr}=$price;
$new_tariffs_hash{$live_product_id}{'tariff_start_date'}=$tariff_start_date;
$new_tariffs_hash{$live_product_id}{'tariff_end_date'}=$tariff_end_date;
$new_tariffs_hash{$live_product_id}{'nights_on_first_tariff'} = $nights_on_first_tariff;
$new_tariffs_hash{$live_product_id}{'nights_on_second_tariff'} = $nights_on_second_tariff;
Made a mistake in my first post.

bazz
08-21-2009, 06:34 PM
Suddenly, I feel inadequate. :(

I'll read over that again later and see if I can incorporate it with a bit of modification.

Thank you

bazz

Jolle
08-21-2009, 07:58 PM
Don't know if you know it already, but you might get some insights in multiple layer hashes and references from the book of Simon Cozens :

http://blob.perl.org/books/beginning-perl/3145_Chap03.pdf : basic introduction in single hashes and arrays (not so interesting if you know that stuff already)

http://blob.perl.org/books/beginning-perl/3145_Chap07.pdf : use of references to build multiple layer arrays and hashes (that might be of value for you)

greetz



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum