Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

using map to generate a hash of hash

by Sihal (Pilgrim)
on Nov 07, 2002 at 14:09 UTC ( #211066=perlquestion: print w/replies, xml ) Need Help??
Sihal has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks,

I'm playing around with map a little.

My problem is the following:
I have a string looking like this :
"abcd.........abcd.....abcd"
where a,b,c,d are the stuff i'm looking for, and the dots misc stuff I don't need.

Now what I'm trying to do is : match globally this string: this gives me an array that looks like this: [a,b,c,d,a,b,c,d,....] as many times as they are found. This is the easy part.

Now I want to map this to an hash looking like this: $hash{'a'}=[something=>'b',another=>'c' ]

To do this i thought, why not use map? But I don't understand how to take my 4 values and dump them in my hash, since map goes on 1 element of the list at a time.... Can somebody provide some help?

My mapping looks like this
%hash =map{??????} ( $content =~ /expr/) ; Thanx.

Replies are listed 'Best First'.
Re: using map to generate a hash of hash
by jdporter (Canon) on Nov 07, 2002 at 14:33 UTC
    If the intent really is to do the hash assignment in one swoop, with exactly one map, then the key to your solution probably lies in restructuring your regex match, so that it produces one list item per intended hash item.

    Can you show your current regex?

    You might also want to show more realistic data. E.g. I can't tell if those "a", etc. are really one literal character, as shown, or if those are placeholders for longer, variable patterns. If the former, you should be able to do this:     /(abcd)/g
    Then your map could look like this:

    map { my( $a, $b, $c, $d ) = split //; $a => { something => $b, another => $c } }
    But I suspect that your situation is actually rather more complicated than that.
      Yes, you're correct, my situation is more complicated.

      here is the string i'm matching:
      4913|@rt Pages Photos|Paris 19|75019|31 Ave Secretan

      Where the a,b,c,d are the strings beetween the pipes. Of course, there are about 500 different stores that I wanna match in my string

      The regex:
      ($content =~ m/^(\d+) \| ([^\|]+) \| ([^\|]+) \| (\d\d\d\d\d) \| (.+) + /xg)
      And I don't mind using more than one map,I'd just like to do it in as little lines as possible.

      Thanks a lot for the help.
        Is each one of these records on a line by itself?
        If so, then you want either to read the input line by line, or split the content on newlines first.

        And then you probably want to use split rather than a regex, to parse each record.

        Example:

        my %hash = map { my( $a, @b ) = split /\|/; defined $a ? ( $a => { @b } ) : () } split /\n+/, $content;
        Also, I wonder what the subhashes are supposed to look like. Do you have a fixed set of keys, and only the values come from the input records? In that case, you could have something like this:
        my @subhash_keys = qw( something another ); my %hash = map { my( $a, @b ) = split /\|/; my %b; @b{ @subhash_keys } = @b; defined $a ? ( $a => \%b ) : () } split /\n+/, $content;
        Of course, ultimately, you may find it more convenient to use a more traditional for loop. It would also be more efficient for large input files.

        It's somewhat confusing that you keep talking of 4 pices of data s,b,c,d, however your sample string contains 4 pieces and your regex is capturing 5 peices?

        Also, in your original post, you show this

        $hash{'a'}=[something=>'b',another=>'c' ]

        which is assigns an array of 4 elements to the hash keyed by a, but the two of the 4 elements are not any of b,c,d(or e?), and two are.

        Further, you show the construction of the hash using fat commas (=>) which is usually use for setting up a hash, but in the context of an anonymous array [], means exactly the same (but in a confusing way) as an ordinary comma ','.

        I think some clarification is required here.


        Nah! You're thinking of Simon Templar, originally played (on UKTV) by Roger Moore and later by Ian Ogilvy
Re: using map to generate a hash of hash
by thraxil (Prior) on Nov 07, 2002 at 14:27 UTC
    But I don't understand how to take my 4 values and dump them in my hash, since map goes on 1 element of the list at a time....

    that's about right. someone clever might be able to come up with a way to do what you want using map, but really that's the wrong tool for the job. a simple for loop would work much better and probably be clearer.

    anders pearson

      Well, I'm aware that I can do that more easily using a loop but I'm very curious to find out if and how this can be solved with map.
      I'm sorry but an emergency is knocking on the door; so I can't reply to jdporter and dingus right now
      However both of your posts are very interesting to me, I'll reply ASAP
Re: using map to generate a hash of hash
by dingus (Friar) on Nov 07, 2002 at 15:00 UTC
    As was stated by "jdporter on Nov 07, 2002 at 10:33" you pobably need to restructure the regex such that you can get all 4 variables in $1 $2 $3 (and $4 ?) and then you can do
    while ($content =~ /(e)(x)(p)r/g) { $hash{$1}={ something=>$2, another=>$3 } }
    But assuming that the regex is NOT under your control and that you have in fact received from somewhere else a list of N items (where N is divisble by 4) and you wish to process the entire list without creating an intermedate array then the following will do the trick (and no doubt someone could rewrite this s.t. it uses map and is on one line):
    my $c=0; my @subkeys = ('', 'something', 'another', 'third'); my $k; for ( split(/(?:box)?\n\s*/) ) { if ($c) { ${$hash{$k}}}{$subkeys[$c]}=$_; } else {$k = $_ } $c = ($c + 1)%4; }
    I also note that you wrote [something=>'b',another=>'c' ] which is probably wrong. If you want a hash it should be { }, if you want an array then you don't need the 'something=>' bits.

    Dingus


    Enter any 47-digit prime number to continue.
      I'm sorry but an emergency is knocking on the door; so I can't reply to jdporter and dingus right now However both of your posts are very interesting to me, I'll reply ASAP

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://211066]
Approved by Jenda
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (10)
As of 2018-11-12 20:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My code is most likely broken because:
















    Results (144 votes). Check out past polls.

    Notices?