Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

quickly create reference to boring hash.

by tford (Beadle)
on May 13, 2008 at 21:58 UTC ( #686383=perlquestion: print w/replies, xml ) Need Help??
tford has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on lexing mathematical expressions and I'm constructing a toy example of a non-deterministic finite automaton.

I've decided that the transition tables should be stored in hashes so that input characters can actually serve as keys to the hash. It is possible that some inputs may map to more than one transition, so I've also decided that each key (input character) should have a reference to an anonymous array as its value. If the input character only specifies one transition, then the value should be a reference to an array containing only one element!

This way of thinking produces some states with pretty boring transition tables. For example, a state that represents the situation of "about to read an identifier," which I've called 'id_0', might have a transition table which looks like the following.

id_0 => {a=>['id_1'], b=>['id_1'], . . . z=>['id_1']}

Now, in my toy example, I've constructed this state using the following technique.

use strict; use warnings; my @array = ('a'..'z'); my %hash = map {$_ => ['id_1']} @array; my $hashref = \%hash; my %states = (id_0 => $hashref); print("The first transition for (state,input) pair (id_0,x) is\n"); print($states{id_0}->{x}->[0]);

My question is, "Is there a way to do this without the intermediate %hash variable?"

Any help will be appreciated, whether it's a "Here's how you do it" one liner, or a "Why do you want to it that way, when you could do it this way" type of thing.


Replies are listed 'Best First'.
Re: quickly create reference to boring hash.
by ikegami (Pope) on May 13, 2008 at 22:07 UTC

    Is there a way to do this without the intermediate %hash variable?

    my %hash = map {$_ => ['id_1']} @array; my $hashref = \%hash;

    can be written as

    my $hashref = { map {$_ => ['id_1']} @array };

    Curlies create a hash, initialize it with the list in the curlies, and returns a reference to the new hash.

Re: quickly create reference to boring hash.
by moritz (Cardinal) on May 13, 2008 at 22:04 UTC
    my %states; $states{id_0}{$_} = ['id_1'] for 'a'..'z';
Re: quickly create reference to boring hash.
by FunkyMonk (Chancellor) on May 13, 2008 at 22:08 UTC
    {} can be used to create a hashref, so...
    my @array = ('a'..'z'); my %states = (id_0 => { map {$_ => ['id_1']} @array }); print("The first transition for (state,input) pair (id_0,x) is\n"); print($states{id_0}->{x}->[0]);

    Unless I state otherwise, all my code runs with strict and warnings
Re: quickly create reference to boring hash.
by GrandFather (Sage) on May 14, 2008 at 01:45 UTC
    my $hashref; @{$hashref}{@array} = (['id_1']) x @array;

    Perl is environmentally friendly - it saves trees
Re: quickly create reference to boring hash.
by starbolin (Hermit) on May 14, 2008 at 02:06 UTC

    A hash would not appear to be the ideal data structure to contain your transition tables. A hash contains a lot of magic behind the scenes to insure that each key maps to exactly one container in the internal structure. A precaution which your application expressly does not need. A hash also has to work over a wide population of keys and insure that the population of keys is distributed evenly over the internal storage. Your, admittedly simple, example has a fixed and small key range of a..z which could be stored sequentially.

    It would seem from your example code that needs would be served by a simple array with a symbolic index. Perl supplies something called a pseudo-hash though I don't know how efficient it is. The module Hash::Util allows a similar functionality with "locked" hashes.

    I'm not sure if this is as efficient as I would like. Question for perlmonks; Does Perl actually create an array here or otherwise optimize or do I still suffer from the overhead of hash lookups?

    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

      Except my previous post is wrong. Perl hashes are so dang slick that they beat all my hackery with arrays and pseudo-hashes. In deference to those who say CPU cycles DO NOT MATTER!, the difference is small enough that the OP could chose the method that is the most readable.

      s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
        Pseudo-hashes have been deprecated; they never worked really well in the first place, and don't work at all in newer Perls. Using them will lock your code into a particular version of Perl, which is of course inadvisable.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://686383]
Approved by ikegami
and monks are getting baked in the sun...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2018-05-24 22:00 GMT
Find Nodes?
    Voting Booth?