Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

create 3 dimensional hash using map 1

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
GB
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
 
Hi

1DMF said:
Plus countless variations
No variation with arrays instead of array references ?

I mean :
Perl:
%free_slots [teal]=[/teal] [b][black]map[/black][/b] [teal]{[/teal]$_ [teal]=>[/teal] [teal]{[/teal] [b][black]map[/black][/b] [teal]{[/teal]$_ [teal]=>[/teal] [teal]{[/teal][b][black]map[/black][/b] [teal]{[/teal]$_ [teal]=>[/teal] [COLOR=#993399]1[/color][teal]}[/teal][teal][highlight]([/highlight][/teal][COLOR=#993399]1[/color][teal],[/teal][COLOR=#993399]2[/color][teal],[/teal][COLOR=#993399]3[/color][teal],[/teal][COLOR=#993399]4[/color][teal],[/teal][COLOR=#993399]5[/color][teal][highlight])[/highlight][/teal][teal]}}[/teal][teal][highlight]([/highlight][/teal][COLOR=#993399]1[/color][teal],[/teal][COLOR=#993399]2[/color][teal],[/teal][COLOR=#993399]3[/color][teal][highlight])[/highlight][/teal][teal]}}[/teal][teal][highlight]([/highlight][/teal][i][COLOR=#009900]'L'[/color][/i][teal],[/teal][i][COLOR=#009900]'R'[/color][/i][teal][highlight])[/highlight];[/teal]

Feherke.
feherke.ga
 
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...
() hash
{} hashref
() array
[] arrayref

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

Thanks Feherke :)

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'}};
    }
    
    [highlight #FCE94F]# 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'}}
[/highlight]         
    # 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
 
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 :
Perl:
[gray]# remove empty dimensions[/gray]
[b][black]foreach[/black][/b] [b][black]my[/black][/b] $pos [teal]([/teal][b][black]keys[/black][/b] %free_slots[teal])[/teal] [teal]{[/teal] [b][black]foreach[/black][/b] [b][black]my[/black][/b] $ord [teal]([/teal][b][black]keys[/black][/b] $free_slots[teal]{[/teal]$pos[teal]}[/teal][teal])[/teal] [teal]{[/teal] [b][black]delete[/black][/b] $free_slots[teal]{[/teal]$pos[teal]}[/teal][teal]->[/teal][teal]{[/teal]$ord[teal]}[/teal] [b][black]unless[/black][/b] [b][black]keys[/black][/b] $free_slots[teal]{[/teal]$pos[teal]}[/teal][teal]->[/teal][teal]{[/teal]$ord[teal]}[/teal] [teal]}[/teal] [teal]}[/teal]


Feherke.
feherke.ga
 
Well, I prefer generic approaches.
exactly, me too, and why I asked ;-)

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 :-(

"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
 
Hi

1DMF said:
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 :-(
Oh, you mean a less loopy solution. Well, there is [tt]grep[/tt] for that purpose. But sadly I only managed to replace one of the loops with [tt]grep[/tt], so one still remains :
Perl:
[teal]%[/teal][teal]{[/teal][navy]$v[/navy][teal]}[/teal] [teal]=[/teal] [b][black]map[/black][/b] [teal]{[/teal] [navy]$_[/navy] [teal]=>[/teal] [navy]$v[/navy][teal]->[/teal][teal]{[/teal][navy]$_[/navy][teal]}[/teal] [teal]}[/teal] [b][black]grep[/black][/b] [teal]{[/teal] [b][black]keys[/black][/b] [navy]$v[/navy][teal]->[/teal][teal]{[/teal][navy]$_[/navy][teal]}[/teal] [teal]}[/teal] [b][black]keys[/black][/b] [navy]$v[/navy] [b][black]while[/black][/b] [teal]([/teal][navy]$k[/navy][teal],[/teal] [navy]$v[/navy][teal])[/teal] [teal]=[/teal] [b][black]each[/black][/b] [navy]%free_slots[/navy][teal];[/teal]
But wondering whether it is more efficient in any detail.


Feherke.
feherke.ga
 
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
 
Hi

1DMF said:
I can't see how the empty dimensions get removed.
Not the empty hashes are removed, but the non-empty hashes kept. [tt]grep[/tt] filters out the keys for which the value is an empty hash.


Feherke.
feherke.ga
 
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
 
Hi

1DMF said:
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 [tt]foreach[/tt] was challenging. From that point it already accomplished its goal : was fun to write it. :)


Feherke.
feherke.ga
 
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
 
Hi

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


Feherke.
feherke.ga
 
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
 
Hi

1DMF said:
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
 
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
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top