having trouble with hash of arrays...

Discussion in 'Perl Misc' started by bjobrien62@gmail.com, Jul 3, 2013.

  1. Guest

    This is confusing me...
    I have a patient id and that patient id can have a list of patient names (each with different spelling, but the same person)

    my %hash = ();
    my $pid = "Patient ID";
    my $pname = "Patient Name";

    I check to see if there is an entry in the hash for patient ID.
    If there is then I want the array of Patient Names for the Patient ID.
    Then I want to see if this spelling is found in the Array.
    If it is do nothing, if it isn't then I add the new spelling to the array then set that array as the value for the hash pid.


    if (exists($hash{$pid})) {

    $pnames = $hash{$pid};
    @found = grep(/$pname/, @pnames);
    $size = @found;

    if ($size == 0) {
    push(@$names, $pname);
    $hash{$pid} = [ @foo ];
    }
    } else {
    $hash{$pid} = [ $pname ];
    }

    Then I want to print out the list...

    my $patid = "";

    foreach my $patid (keys %hash) {
    print "The spellings for $patid are\n";
    foreach (@{$hash{$patid}}) {
    print "\t$_\n";
    }
    }
     
    , Jul 3, 2013
    #1
    1. Advertising

  2. Ivan Shmakov Guest

    >>>>> bjobrien62 <> writes:

    > This is confusing me...


    What specifically?

    [...]

    > if (exists($hash{$pid})) {
    > $pnames = $hash{$pid};
    > @found = grep(/$pname/, @pnames);


    The problem with grep () is that it will scan through /all/ the
    list, instead of stopping on the first match.

    > $size = @found;
    > if ($size == 0) {
    > push(@$names, $pname);
    > $hash{$pid} = [ @foo ];
    > }
    > } else {
    > $hash{$pid} = [ $pname ];
    > }


    ... Overall, I'd just use a (second) hash instead, as in:

    $hash{$pid}->{$pname} = 1
    unless (exists ($hash{$pid})
    && exists ($hash{$pid}->{$pname}));

    > Then I want to print out the list...


    > my $patid = "";


    What is the above statement for?

    > foreach my $patid (keys %hash) {
    > print "The spellings for $patid are\n";
    > foreach (@{$hash{$patid}}) {
    > print "\t$_\n";
    > }
    > }


    The inner foreach () loop seems a bit superfluous here.
    Consider, e. g.:

    foreach my $patid (keys %hash) {
    print "The spellings for $patid are\n";
    local ($,, $\)
    = ("\t", "\n");
    print ("", keys (%{$hash{$patid}}));
    }

    Naturally, join () may be used instead of setting $,, like:

    print ("The spellings for ", $patid, " are\n",
    "\t", join ("\t", keys (%{$hash{$_}})), "\n");
    foreach (keys (%hash));

    Consider also applying sort () to the keys () of the hashes.

    --
    FSF associate member #7257
     
    Ivan Shmakov, Jul 3, 2013
    #2
    1. Advertising

  3. On 7/2/2013 5:11 PM, wrote:
    > This is confusing me...
    > I have a patient id and that patient id can have a list of patient names (each with different spelling, but the same person)
    >
    > my %hash = ();
    > my $pid = "Patient ID";
    > my $pname = "Patient Name";
    >
    > I check to see if there is an entry in the hash for patient ID.
    > If there is then I want the array of Patient Names for the Patient ID.
    > Then I want to see if this spelling is found in the Array.
    > If it is do nothing, if it isn't then I add the new spelling to the array then set that array as the value for the hash pid.
    >
    >
    > if (exists($hash{$pid})) {
    >
    > $pnames = $hash{$pid};
    > @found = grep(/$pname/, @pnames);

    ^^^^^^^
    @{$pnames}
    > $size = @found;
    >
    > if ($size == 0) {
    > push(@$names, $pname);
    > $hash{$pid} = [ @foo ];
    > }
    > } else {
    > $hash{$pid} = [ $pname ];
    > }


    @$names and @foo look wrong... old code fragments perhaps?


    Since you only want to add new spellings, you could shorten it all down
    to a line or two, eg,

    unless ( grep( /^$pname$/, @$pnames ) {
    push( @{ $hash{$pid} }, $pname );
    }



    >
    > Then I want to print out the list...
    >
    > my $patid = "";

    ^^^^^^^^^^^^^^^
    unneeded

    >
    > foreach my $patid (keys %hash) {
    > print "The spellings for $patid are\n";
    > foreach (@{$hash{$patid}}) {
    > print "\t$_\n";
    > }
    > }
    >


    Other than the unneeded line, this looks ok though.

    --
    Charles DeRykus
     
    Charles DeRykus, Jul 3, 2013
    #3
  4. Dr.Ruud Guest

    On 03/07/2013 08:44, Charles DeRykus wrote:

    > unless ( grep( /^$pname$/, @$pnames ) {
    > push( @{ $hash{$pid} }, $pname );
    > }


    Names can contain regexp-metacharacters.

    grep { $_ eq $pname } @$pnames

    --
    Ruud
     
    Dr.Ruud, Jul 3, 2013
    #4
  5. writes:
    > if (exists($hash{$pid})) {
    >
    > $pnames = $hash{$pid};
    > @found = grep(/$pname/, @pnames);


    @pnames is not the same as the anonymous array $pnames refers to. That
    would be @$pnames.

    /$pname/ is a regex match which will return true if one of the input
    elements matches the regex $pname somewhere. Eg, if $pname was 'Henry
    I.', that would match 'John Henry Ibsen'. This should be something
    like

    /^\Q$pname\E$/

    This anchors the match at the beginning and end of the string, eg,
    'Henry' will match 'Henry' and not 'John Henry' and quotes any
    regex-metacharacters in $pname.

    > $size = @found;


    You can as well use $size = grep(...) as grep returns the number of
    elements it found in scalar context.


    > if ($size == 0) {
    > push(@$names, $pname);


    @$names is not the same as @$pnames. The strict module/ pragma is very
    helpful for catching these kind of mistakes.
     
    Rainer Weikusat, Jul 3, 2013
    #5
  6. # this is what you want


    use strict;
    use warnings;
    my %hash;

    while (<DATA>)
    {
    my ($pid, $pname) = $_ =~/^(.*?),(.*?)\s*$/;

    if (exists $hash{$pid})
    {
    unless ( $pname ~~ @{$hash{$pid}->{'names'}} )
    {
    push @{$hash{$pid}->{'names'}} , $pname
    }
    }
    else
    {
    $hash{$pid}->{'value'} = $pname;
    $hash{$pid}->{'names'} = [ $pname ]
    }
    }


    use Data::Dumper; print Dumper \%hash;

    __DATA__
    foo,foo name
    foo,fooname
    foo,fo oname
    foo,fooname
    goo,gooname
    goo,goo name
    goo,gooname
     
    George Mpouras, Jul 4, 2013
    #6
  7. Dr.Ruud Guest

    On 04/07/2013 20:45, George Mpouras wrote:

    > while (<DATA>) {
    > my ($pid, $pname) = /^(.*?),(.*?)\s*$/;


    Be aware that the '(.*?)\s*$' at the end just means '(.*)'.




    What meaning where you looking for?

    Maybe this: '(.*\S)\s*$'.
    (but then the last field can't be empty).

    --
    Ruud
     
    Dr.Ruud, Jul 5, 2013
    #7
  8. Dr.Ruud Guest

    Ignore this, I sent it by accident.

    On 05/07/2013 10:03, Dr.Ruud wrote:
    > On 04/07/2013 20:45, George Mpouras wrote:
    >
    >> while (<DATA>) {
    >> my ($pid, $pname) = /^(.*?),(.*?)\s*$/;

    >
    > Be aware that the '(.*?)\s*$' at the end just means '(.*)'.
    >
    >
    >
    >
    > What meaning where you looking for?
    >
    > Maybe this: '(.*\S)\s*$'.
    > (but then the last field can't be empty).
    >


    I was testing and found out I was wrong, and need more coffee:

    perl -wle '
    $_ = "x,y \n";
    my ($pid, $pname) = /^(.*?),(.*?)\s*$/;
    print "<$pid>,<$pname>";
    '
    <x>,<y>

    --
    Ruud
     
    Dr.Ruud, Jul 5, 2013
    #8
  9. Guest

    On Friday, July 5, 2013 11:03:30 AM UTC+3, Dr.Ruud wrote:
    > On 04/07/2013 20:45, George Mpouras wrote:
    >
    >
    >
    > > while (<DATA>) {

    >
    > > my ($pid, $pname) = /^(.*?),(.*?)\s*$/;

    >
    >
    >
    > Be aware that the '(.*?)\s*$' at the end just means '(.*)'.
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > What meaning where you looking for?
    >
    >
    >
    > Maybe this: '(.*\S)\s*$'.
    >
    > (but then the last field can't be empty).
    >
    >
    >
    > --
    >
    > Ruud




    you are not correct, the (.*?)\s*$/ is not equal to '(.*)'.
    It is not greedy and you do not catch any \n \r \v at $2
    So this way you can avoid the function
    chomp $_;
    The .* you mention is catching also the new lines.
     
    , Jul 5, 2013
    #9
  10. Guest

    hey , sorry , I did not see your previous message.
     
    , Jul 5, 2013
    #10
  11. wrote:
    > On Friday, July 5, 2013 11:03:30 AM UTC+3, Dr.Ruud wrote:
    >> On 04/07/2013 20:45, George Mpouras wrote:
    >>>
    >>> while (<DATA>) {
    >>> my ($pid, $pname) = /^(.*?),(.*?)\s*$/;

    >>
    >> Be aware that the '(.*?)\s*$' at the end just means '(.*)'.
    >>
    >> What meaning where you looking for?
    >>
    >> Maybe this: '(.*\S)\s*$'.
    >> (but then the last field can't be empty).

    >
    > you are not correct, the (.*?)\s*$/ is not equal to '(.*)'.
    > It is not greedy and you do not catch any \n \r \v at $2
    > So this way you can avoid the function
    > chomp $_;
    > The .* you mention is catching also the new lines.


    No. The . character class does not match a newline (unless the regular
    expression uses the /s option.)




    John
    --
    Any intelligent fool can make things bigger and
    more complex... It takes a touch of genius -
    and a lot of courage to move in the opposite
    direction. -- Albert Einstein
     
    John W. Krahn, Jul 6, 2013
    #11
  12. (.*)$/

    will match the new line like it or not
     
    George Mpouras, Jul 6, 2013
    #12
  13. "George Mpouras"
    <> wrote:
    >(.*)$/
    >
    >will match the new line like it or not


    No, it doesn't. From "perldoc perlre":
    $ Match the end of the line (or before newline at the end)

    In so far it is the same as the zero width(!!!) assertion
    \Z Match only at end of string, or before newline at the end
    which does not match the new line, either.

    jue
     
    Jürgen Exner, Jul 6, 2013
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Philipp
    Replies:
    21
    Views:
    1,189
    Philipp
    Jan 20, 2009
  2. rp
    Replies:
    1
    Views:
    593
    red floyd
    Nov 10, 2011
  3. Adam Akhtar
    Replies:
    5
    Views:
    677
    Adam Akhtar
    Mar 25, 2008
  4. Derek Cannon

    Trouble with Pushing Arrays to Arrays

    Derek Cannon, Apr 17, 2010, in forum: Ruby
    Replies:
    5
    Views:
    120
    David A. Black
    Apr 17, 2010
  5. R^3
    Replies:
    5
    Views:
    149
Loading...

Share This Page