having trouble with hash of arrays...

B

bjobrien62

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";
}
}
 
I

Ivan Shmakov

bjobrien62 said:
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.
 
C

Charles DeRykus

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.
 
R

Rainer Weikusat

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.
 
G

George Mpouras

# 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
 
D

Dr.Ruud

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).
 
D

Dr.Ruud

Ignore this, I sent it by accident.

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>
 
G

gravitalsun

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.
 
J

John W. Krahn

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
 
J

Jürgen Exner

"George Mpouras"
(.*)$/

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top