learnperl has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
This is the first iteration of my thinking process to handle this issues, What I am trying to do is have format that prints values in an array with seperations but without repeating the the prefix of the sentence (I know the above words doesn't mean anything I tried my best to explain in words..)
This is what I really want to do,
The name William could be Willy, Will, Bill
So here is the code..

entire %nicknames is too big to put it here, I know you guys get the idea right ..

#hash table that contains nicknames %nicknames = ( Abe => 'Abraham', Abram => 'Abraham Abe', Bill => 'William Will', Will => 'Bill William willy', );

Part of my code which handles the above hash


=pod Idea is to match the nick name with the correct first name and return the correct name which matches with the user entered nick name. =cut sub matchNickname { my $nickTemp; foreach my $key(keys %nicknames) { my $value = $nicknames{$key}; if(lc $name eq lc $key){ print "user typed ".$name." Match the key ".$key." and val +ue is $value\n\n"; $nickTemp = $value; @nickArray = split '\W+', $nickTemp; foreach $nickTemp(@nickArray) { if($DEBUG){print "The name $name could be <$nickTemp> +or ";} } } #print "$key ==> $value\n"; #print "$nickTemp\n"; } #print "Value of nickTemp is $nickTemp\n"; }
Thanks in advance
LearnPerl

Replies are listed 'Best First'.
Re: Help on format or better way to do..?
by toolic (Bishop) on Nov 27, 2007 at 00:23 UTC
    Your nicknames hash seems a little strange because the keys are nicknames, but the values are a mixture of nicknames and formal names. It might be easier to access the data you want if you were to organize it differently. For example, I replaced your "nicknames" hash with a hash named "formal_name":
    use warnings; use strict; my %formal_name = ( bill => 'william', will => 'william', abe => 'abraham' ); print_formal_name('will'); print_formal_name('sam'); print_all_nicknames('wiLLiam'); print_all_nicknames('thomas'); sub print_formal_name { my $nickname = shift; if (exists $formal_name{lc $nickname}) { print "The formal name for $nickname is ", ucfirst $formal_nam +e{lc $nickname}, ".\n"; } else { print "There is no formal name for $nickname.\n"; } } sub print_all_nicknames { my $formalname = shift; my @nicknames; for my $nickname (keys %formal_name) { if ($formal_name{$nickname} eq lc $formalname) { push @nicknames, ucfirst $nickname . ', '; } } if (@nicknames) { $nicknames[$#nicknames] =~ s/, //; print ucfirst lc $formalname, " has these nicknames: ", @nickn +ames, ".\n"; } else { print ucfirst lc $formalname, " has no nicknames.\n"; } }
    This prints:
    The formal name for will is William. There is no formal name for sam. William has these nicknames: Will, Bill. Thomas has no nicknames.
      Total agreement with your suggestions -- just wanted to add that the "print_all_nicknames" function would be easier if there's a hash of arrays built from the original "%formal_name" hash:
      my %formal_name = ( bill => 'william', will => 'william', willie => 'william', billie => 'william', bob => 'robert', bobbie => 'robert', ... ); my %nick_names; for my $nick ( keys %formal_name ) { push @{$nick_names{$formal_name{$nick}}}, ucfirst $nick; } ... print_all_nicknames( 'William' ); sub print_all_nicknames { my $formalname = lc shift; if ( exists( $nick_names{$formalname} )) { print ucfirst $formalname, " has these nicknames: ", join( ", ", @{$nick_names{$formalname}} ), "\n"; } else { print ucfirst $formalname, " has no nicknames.\n"; } }
      (updated to fix sub name -- and to add missing curlies, as pointed out below by toolic)
        Good idea. But, I needed to add some curlies to pass strictures with your code:
        push @{ $nick_names{$formal_name{$nick}} }, ucfirst $nick;

      Thanks
      I actually started with the hash you mentioned and decided to go for the mixture because lets say if we type Bill and the actual person's name for Bill could be William so I thought I have to handle that scenario..
      example
      Main Reson that I changed the structure of the hash is below mention concept.. Do you think I am on the wrong path or does it make sense...
      A => B, C, D, E
      B => A, F, G, H

      Thanks
      LearnPerl
        I don't know what you mean by "the mixture", and I don't understand how the "scenario" with "Bill" vs. "William" is different from what was handled in the earlier replies by toolic and me.

        If "B,C,D,E" are all nicknames for "A", and "A,F,G,H" are all nicknames for "B", and if the purpose of this data structure is to provide a one-shot lookup for a given string (i.e. to get the "immediate nickname set" for that string), then okay, that structure makes sense. (Well, sort of, I guess... but are you saying you have cases where A is a nickname for B and B is also a nickname for A? I'm having trouble with that.)

        But if the purpose is to pursue all possible "respelling" relations in a set (e.g. "A" can be respelled as any of "B,C,D,E", and for each of those, use the same structure to find all possible respellings), then you have a problem of circularity: A can be respelled as B, which can be respelled as A, which can be respelled as B, which... (infinite loop).

        Actually, it's not at all clear now what you are really trying to do, so I'm not sure what advice to give about the data structure. There are two basic directions that seem to be at issue:

        1. tracking many-to-one relations: for each member in a set of N "nicknames", relate it to a specific member in a set of M "real" names, where M < N, and two or more nicknames can refer to the same real name; this involves a simple hash where each hash key points to exactly one value, but the hash values can be non-unique.

        2. tracking one-to-many relations: for each member in a set of M "real" names, list the set of one or more "nicknames" that are synonymous; this involves a hash of arrays, and if this structure is derived from the many-to-one set described above, it cannot be the case that a given array value shows up under more than one hash key (because each "nickname" relates to only one "real name").

        If the structure you are looking for is not one of those two, then you need to be more clear about what kind of structure you are looking for and how you want it to organize things. You seem to be giving us simplified fake examples, and maybe they are too simple or maybe they don't accurately reflect your data or your task. What are you really trying to do?

        UPDATE: There is a third direction you might be thinking about: many-to-many relations, e.g. a nickname like "Chas" might relate to both "Charles" and "Chastity", but "Chuck" is also a nickname for "Charles". This is another hash of arrays, where some array values (the "real" names in this case) can occur with two or more hash keys. In any case, the important thing is that the hash keys are one set of entities (e.g. nicknames), and the hash values, whether scalars or arrays, are a distinct set of entities (e.g. real names). Just don't get them confused.

Re: Help on format or better way to do..?
by FunkyMonk (Bishop) on Nov 26, 2007 at 22:21 UTC
    You could use join:
    print join ", ", @nickArray;

    That prints all the elements of @nickArray separated by a comma and a space. Or, you could set $, (output field seperator) to ", ":

    $, = ", "; print @nickArray;

    If you use that, you're better off localising the effect of $,:

    { local $, = ", "; print @nickArray; }

    See perlvar for more on $,.