In search of elegant code - searching keys of hashes in array

D

David Filmer

Suppose I have an array of hashes of names and social-security
numbers:

@ARRAY = (
{ first => 'John', last => 'Doe', ssn => '123-45-6789' },
{ first => 'Fred', last => 'Ree', ssn => '9876-54-321' }
);

Now suppose I want to print an error if any particular SSNs (say
'234-56-7890' and '0987-65-4321') are not found in my @ARRAY.
Obviously I can't just grep the array. I could build an intermediate
hash (%SSN) like this:

for (@ARRAY) { $SSN{$$_{'ssn'}}++ }
for (qw/234-56-7890 0987-65-4321/) {
print "Not found: $_\n" unless $SSN{$_}
}

but that's REALLY ugly (I don't like the creation of the intermediate
%SSN hash). I would appreciate suggestions for a more elegant
approach.
 
E

Eric J. Roode

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

(e-mail address removed) (David Filmer) wrote in
Suppose I have an array of hashes of names and social-security
numbers:

@ARRAY = (
{ first => 'John', last => 'Doe', ssn => '123-45-6789' },
{ first => 'Fred', last => 'Ree', ssn => '9876-54-321' }
);

Now suppose I want to print an error if any particular SSNs (say
'234-56-7890' and '0987-65-4321') are not found in my @ARRAY.
Obviously I can't just grep the array. I could build an intermediate
hash (%SSN) like this:

for (@ARRAY) { $SSN{$$_{'ssn'}}++ }
for (qw/234-56-7890 0987-65-4321/) {
print "Not found: $_\n" unless $SSN{$_}
}

but that's REALLY ugly (I don't like the creation of the intermediate
%SSN hash). I would appreciate suggestions for a more elegant
approach.

I can't think of a better way. I think it's uglier to loop over the
@ARRAY each time you want to check a SSN.

Perhaps you can skip the (ugly?) creation of the intermediate hash by
representing your data differently? Or at least, maintaining the
%SSN hash alongside your @ARRAY data?

- --
Eric
$_ = reverse sort $ /. r , qw p ekca lre uJ reh
ts p , map $ _. $ " , qw e p h tona e and print
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (MingW32) - WinPT 0.5.13

iD8DBQE/192QY96i4h5M0egRAot5AJ9RFzaafodA6bTCfdpkDZhb+GsP1gCg+gXY
4nWr8yxFkPsHeTXaO9DGP44=
=ZrTm
-----END PGP SIGNATURE-----
 
J

Jim Keenan

David Filmer said:
Suppose I have an array of hashes of names and social-security
numbers:

@ARRAY = (
{ first => 'John', last => 'Doe', ssn => '123-45-6789' },
{ first => 'Fred', last => 'Ree', ssn => '9876-54-321' }
);

Now suppose I want to print an error if any particular SSNs (say
'234-56-7890' and '0987-65-4321') are not found in my @ARRAY.
Obviously I can't just grep the array. I could build an intermediate
hash (%SSN) like this:

for (@ARRAY) { $SSN{$$_{'ssn'}}++ }
for (qw/234-56-7890 0987-65-4321/) {
print "Not found: $_\n" unless $SSN{$_}
}

but that's REALLY ugly (I don't like the creation of the intermediate
%SSN hash). I would appreciate suggestions for a more elegant
approach.

Can you store your data in the form of a hash keyed by the SSN? After all,
setting aside fraud, the SSN uniquely identifies each individual and is made
to order as a hash key:

%SSN = (
123-45-6789 => ['John', 'Doe'],
9876-54-321 => ['Fred', 'Ree'],
);

Note that while the keys in your inner hash ('first', 'last', etc.) make it
easier to read, they don't add any semantic value and their repetition
increases the possibility of typing and coding errors.

jimk
 
I

Iain Chalmers

Jim Keenan said:
Can you store your data in the form of a hash keyed by the SSN?

So long as you keep in mind what a US-centric solution that is...

Iain (I have no SSN, but I _may_ want to buy something from your website)
 
A

A. Sinan Unur

So long as you keep in mind what a US-centric solution that is...

Iain (I have no SSN, but I _may_ want to buy something from your website)

Well, I seriously doubt that this involves an ecommerce site. Entering your
SSN is hardly a prerequisite for making online purchases in the U.S.

Sinan.
 
U

Uri Guttman

DF" == David Filmer said:
Suppose I have an array of hashes of names and social-security
numbers:
@ARRAY = (
{ first => 'John', last => 'Doe', ssn => '123-45-6789' },
{ first => 'Fred', last => 'Ree', ssn => '9876-54-321' }
);
Now suppose I want to print an error if any particular SSNs (say
'234-56-7890' and '0987-65-4321') are not found in my @ARRAY.
Obviously I can't just grep the array. I could build an intermediate
hash (%SSN) like this:

how is that obvious? you must have the classic newbie misconception that
grep only takes regexes which is wrong. grep can take any expression to
test. so you can grep your array easily:

foreach my $ssn ( qw( some ssn values) ) {

@found = grep $_->{ssn} eq $ssn, @array ;
do something based on @found
}

for (@ARRAY) { $SSN{$$_{'ssn'}}++ }
for (qw/234-56-7890 0987-65-4321/) {
print "Not found: $_\n" unless $SSN{$_}
}
but that's REALLY ugly (I don't like the creation of the intermediate
%SSN hash). I would appreciate suggestions for a more elegant
approach.

as someone else said, indexing by ssn is another solution and one i
would recommend. if you do this search often, then building the other
hash is worth it and can be done even simpler than your example:

my %is_ssn ;
@is_ssn{ map $_->{ssn}, @ARRAY } = () ;
# test with exists

or

my %is_ssn = map { $_->{ssn}, 1} @ARRAY ;


but those only tell you if an ssn exists. if you want to find the record
by ssn just replace the 1 with $_ in the second and call the hash
ssn_to_rec or something similar.

uri
 
A

Anno Siegel

David Filmer said:
Suppose I have an array of hashes of names and social-security
numbers:

@ARRAY = (

Upper case names should be reserved for system variables (and a few
exceptions).
{ first => 'John', last => 'Doe', ssn => '123-45-6789' },
{ first => 'Fred', last => 'Ree', ssn => '9876-54-321' }
);

Now suppose I want to print an error if any particular SSNs (say
'234-56-7890' and '0987-65-4321') are not found in my @ARRAY.
Obviously I can't just grep the array.

Why not?

warn "boo: $ssn\n" unless grep $_->{ ssn} eq $ssn, @ARRAY;

It isn't particularly efficient, but perfectly valid.
I could build an intermediate
hash (%SSN) like this:

The only reason to do that would be efficiency.
for (@ARRAY) { $SSN{$$_{'ssn'}}++ }
for (qw/234-56-7890 0987-65-4321/) {
print "Not found: $_\n" unless $SSN{$_}
}

This way you build the hash from scratch each time you need it. It
won't save time over grep that way.
but that's REALLY ugly (I don't like the creation of the intermediate
%SSN hash). I would appreciate suggestions for a more elegant
approach.

If you find you need the hash, build it along with the array @ARRAY,
so that it is always up to date. Then a fast lookup can decide if
a ssn is in the table or not.

Anno
 
G

geoffroy

David said:
Suppose I have an array of hashes of names and social-security
numbers:

@ARRAY = (
{ first => 'John', last => 'Doe', ssn => '123-45-6789' },
{ first => 'Fred', last => 'Ree', ssn => '9876-54-321' }
);

Now suppose I want to print an error if any particular SSNs (say
'234-56-7890' and '0987-65-4321') are not found in my @ARRAY.
Obviously I can't just grep the array. I could build an intermediate
hash (%SSN) like this:

for (@ARRAY) { $SSN{$$_{'ssn'}}++ }
for (qw/234-56-7890 0987-65-4321/) {
print "Not found: $_\n" unless $SSN{$_}
}

but that's REALLY ugly (I don't like the creation of the intermediate
%SSN hash). I would appreciate suggestions for a more elegant
approach.


You can use this sub. it takes one parameter, the ssn.



sub does_ssn_exist{
foreach $hashref (@ARRAY){
if($hashref->{'ssn'} eq $_[0]){retrun 1}
}
return 0;
}


Geoffroy
 

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,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top