×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!
  • Students Click Here

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Jobs

create 3 dimensional hash using map

create 3 dimensional hash using map

create 3 dimensional hash using map

(OP)
Hi,

I want a variable created like so...

CODE

# free slots holding hash
    my $free_slots = {
        'L' => {
            '1' => {
                '1' => 1, 
                '2' => 1, 
                '3' => 1, 
                '4' => 1, 
                '5' => 1
            },
            '2' => {
                '1' => 1, 
                '2' => 1, 
                '3' => 1, 
                '4' => 1, 
                '5' => 1
            }
        },
        'R' => {
            '1' => {
                '1' => 1, 
                '2' => 1, 
                '3' => 1, 
                '4' => 1, 
                '5' => 1
            },
            '2' => {
                '1' => 1, 
                '2' => 1, 
                '3' => 1, 
                '4' => 1, 
                '5' => 1
            },
            '3' => {
                '1' => 1, 
                '2' => 1, 
                '3' => 1, 
                '4' => 1, 
                '5' => 1
            }
        }
    }; 

I thought there would be an easier way to create this so have tried

CODE

%free_slots = map {$_ => { map {$_ => {map {$_ => 1}[1,2,3,4,5]}}[1,2,3]}}['L','R']; 

Plus countless variations, but I can't seem to work it out, is it possible using $_ in a compound expression like this?

1DMF


"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Quote (1DMF)

Plus countless variations
No variation with arrays instead of array references ?

I mean :

CODE --> Perl

%free_slots = map {$_ => { map {$_ => {map {$_ => 1}(1,2,3,4,5)}}(1,2,3)}}('L','R'); 

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)
damn it, I was so close! cry

No I didn't think to use arrays instead of array refs, I was concerned with the hashes involved the parentheses would cause problems...

Quote:


() hash
{} hashref
() array
[] arrayref

... but as map uses @ not \@, I really should have twigged!

Thanks Feherke smile

as an aside, here is the full method

CODE

#############################
# Get avaialbale slots json #
#############################
sub get_free_slots
{
    # Args
    my $self = shift;
    my $page = shift;
    
    # free slots holding hash
    my %free_slots = map {$_ => { map {$_ => {map {$_ => 1}(1,2,3,4,5)}}(1,2,3)}}('L','R');               
    delete $free_slots{'L'}->{'3'};
                            
    # Get banners for specific page    
    my @banners = $self->Members->getSQL('Banner_Adverts','Pos,Ord,Seq',"Page = '$page'",'Pos,Ord,Seq');
        
    # loop and remove unavailable
    for(@banners)
    {           
        delete $free_slots{$_->{'Pos'}}->{$_->{'Ord'}}->{$_->{'Seq'}};
    }
    
    # remove empty dimensions
    if(!scalar(keys $free_slots{'L'}->{'1'})){delete $free_slots{'L'}->{'1'}}
    if(!scalar(keys $free_slots{'L'}->{'2'})){delete $free_slots{'L'}->{'2'}}   
    if(!scalar(keys $free_slots{'R'}->{'1'})){delete $free_slots{'R'}->{'1'}}
    if(!scalar(keys $free_slots{'R'}->{'2'})){delete $free_slots{'R'}->{'2'}}
    if(!scalar(keys $free_slots{'R'}->{'3'})){delete $free_slots{'R'}->{'3'}}
         
    # return free slots json
    return encode_json(\%free_slots);   
} 

Is there a better way to remove the empty dimensions?

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Well, I prefer generic approaches. So if next week you add 'C' beside 'L' and 'R', you not need to copy & paste more code in the cleanup part :

CODE --> Perl

# remove empty dimensions
foreach my $pos (keys %free_slots) { foreach my $ord (keys $free_slots{$pos}) { delete $free_slots{$pos}->{$ord} unless keys $free_slots{$pos}->{$ord} } } 

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)

Quote:

Well, I prefer generic approaches.
exactly, me too, and why I asked winky smile

Though there will only ever be 'L' & 'R' it stands for 'Left' & 'Right', I believe there will only ever be 2 'hands'! But maybe one day they may want to include 'Top' / 'Bottom' etc.

The banner system only allows sky-scraper banners due to the new template design our graphic designer is working on, but no doubt this will change in a few years when they decide it's no longer hip to be square (what is it with the web lately where everyone seems to be getting rid of rounded corners just as us developers get CSS3!), it's like M$ started a trend with Windows 8, M$ trendsetters, who'd have thought it!

There may be a change to the allowed Order (Ord), but unlikely and allowing more than 5 banners in the same place rotating isn't likely to happen either.

The system being developed allows up to 25 banner adverts per page, which is probably overkill already, but you never know, and implementing code that won't require refactoring regardless is always a good idea.

Of course I knew I could loop as you have it. just wondered if there was a more efficient way, but I know not everything in Perl can be done with cool one liners sad

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Quote (1DMF)

Of course I knew I could loop as you have it. just wondered if there was a more efficient way, but I know not everything in Perl can be done with cool one liners sad
Oh, you mean a less loopy solution. Well, there is grep for that purpose. But sadly I only managed to replace one of the loops with grep, so one still remains :

CODE --> Perl

%{$v} = map { $_ => $v->{$_} } grep { keys $v->{$_} } keys $v while ($k, $v) = each %free_slots; 
But wondering whether it is more efficient in any detail.

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)
Yes, I thought potentially grep, but didn't try anything as I feared it would probably yield unreadable code.

By the looks of things I was right! I can't see how the empty dimensions get removed.

You are too clever by half! medal

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Quote (1DMF)

I can't see how the empty dimensions get removed.
Not the empty hashes are removed, but the non-empty hashes kept. grep filters out the keys for which the value is an empty hash.

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)
of course, though I still find the code hard to follow, and as you say, efficiency isn't really an issue especially as there will likely only ever be 25 items in the array of hashes to start with.

Thanks for the help, it's appreciated.

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Quote (1DMF)

I still find the code hard to follow
Honestly, neither I would ever use such code in production.

I wrote it just because your idea to solve it without foreach was challenging. From that point it already accomplished its goal : was fun to write it. smile

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)

Quote:

I wrote it just because your idea to solve it without foreach was challenging. From that point it already accomplished its goal : was fun to write it

I'm glad you found it entertaining, you already earned a medal from me thumbsup2

I've condensed the code a little more and currently have this...

CODE

#############################
# Get avaialbale slots json #
#############################
sub get_free_slots
{
    # args
    my $self = shift;
    my ($page) = $self->_clean_args(@_);
        
    # free slots holding hash
    my %free_slots = map {$_ => { map {$_ => {map {$_ => 1}(1,2,3,4,5)}}(1,2,3)}}('L','R');               
    delete $free_slots{'L'}->{'3'};                           
        
    # get banners for specific page and remove unavailable
    delete $free_slots{$_->{'Pos'}}->{$_->{'Ord'}}->{$_->{'Seq'}} for ($self->Members->getSQL('Banner_Adverts','Pos,Ord,Seq',"Page = '$page'",'Pos,Ord,Seq'));
    
    # remove empty dimensions
    foreach my $pos (keys %free_slots) 
    { 
        foreach my $ord (keys $free_slots{$pos}) 
        { 
            delete $free_slots{$pos}->{$ord} unless keys $free_slots{$pos}->{$ord} 
        }
    }    
         
    # return free slots json
    return encode_json(\%free_slots);   
} 

Yes I am creating a balanced hash with the one liner then having to delete an entire branch ('L'->{'3'}) as 'L'eft can only have max 2 where as 'R'ight has 3.

But I still think that is the neatest way to create the initial data type. I've moved the entire removal of existing banner slots from the holding hash, the SQL fetch to get the banners plus the looping to a one liner.

I don't see it being any less readable than

CODE

# Get banners for specific page    
    my @banners = $self->Members->getSQL('Banner_Adverts','Pos,Ord,Seq',"Page = '$page'",'Pos,Ord,Seq');
        
    # loop and remove unavailable
    for(@banners)
    {           
        delete $free_slots{$_->{'Pos'}}->{$_->{'Ord'}}->{$_->{'Seq'}};
    } 
do you?

I also refactored to have the argument cleansing in the model rather than the view by creating a utility helper method in the model, which has increased DRYness in the view/model as each end point in the view was regexing the input args, but now the model cleanses it's own data with a single helper method.

Dunno if it's elegant, but it seems to be functional!

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Some may say that one-liner is abit lengthy, but personally I still prefer it that way.

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)
Well if char width is an issue I could always code it as

CODE

# Get banners for specific page    
my @banners = $self->Members->getSQL('Banner_Adverts','Pos,Ord,Seq',"Page = '$page'",'Pos,Ord,Seq');  

# loop and remove unavailable       
delete $free_slots{$_->{'Pos'}}->{$_->{'Ord'}}->{$_->{'Seq'}} for @banners; 

But that's just appeasing those who still use 80 char syntax because they still use a terminal style editor instead of a full blown GUI IDE environment on multiple wide screen monitors. lol

But joking aside does it change the performance of the Perl interpreter if you keep your line length shorter?





"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

RE: create 3 dimensional hash using map

Hi

Quote (1DMF)

does it change the performance of the Perl interpreter if you keep your line length shorter?
Certainly not. The line length limit is just a requirement in many open source projects, aiming to keep the countless contributors coding style somehow unified.

However there may be a difference between the one-liner and your latest code, where you declared a separate @banners variable. That extra memory management may require some extra processing time, but I do not expect that difference to be measurable.

But on such fine tuning of the code, better do not count on my words. I have no experience with Perl scripts on high load. Most of my scripts were written for desktop ( CLI or GUI ) and the CGI scripts were just for company's intranet. So two instances almost never run in parallel and performance optimization was reduced to elimination of common programming clumsinesses.

Feherke.
feherke.ga

RE: create 3 dimensional hash using map

(OP)

Quote:

Certainly not. The line length limit is just a requirement in many open source projects, aiming to keep the countless contributors coding style somehow unified.
So it is simply a width constraint on visual style and nothing more.

Like you , most of my code is in a non-high load environment, and the legacy code spaghetti from 10 years ago still performs fast enough even if it isn't as efficient as it could be, but I am always trying to improve the quality and efficiency of any new code I write.

Thanks for your input, it is very much appreciated.

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close