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

Discussion in 'Perl Misc' started by David Filmer, Dec 11, 2003.

  1. David Filmer

    David Filmer Guest

    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.
     
    David Filmer, Dec 11, 2003
    #1
    1. Advertisements

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

    (David Filmer) wrote in
    news::

    > 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-----
     
    Eric J. Roode, Dec 11, 2003
    #2
    1. Advertisements

  3. David Filmer

    Jim Keenan Guest

    "David Filmer" <> wrote in message
    news:...
    > 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
     
    Jim Keenan, Dec 11, 2003
    #3
  4. In article <VnRBb.48$>,
    "Jim Keenan" <> wrote:

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

    --
    'When I first met Katho, she had a meat cleaver in one hand and
    half a sheep in the other. "Come in", she says, "Hammo's not here.
    I hope you like meat.' Sharkey in aus.moto
     
    Iain Chalmers, Dec 11, 2003
    #4
  5. Iain Chalmers <> wrote in news:bigiain-
    -berlin.de:

    > In article <VnRBb.48$>,
    > "Jim Keenan" <> wrote:
    >
    >> 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)


    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.
    --
    A. Sinan Unur

    Remove dashes for address
    Spam bait: mailto:
     
    A. Sinan Unur, Dec 11, 2003
    #5
  6. David Filmer

    Uri Guttman Guest

    >>>>> "DF" == David Filmer <> writes:

    > 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

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
     
    Uri Guttman, Dec 11, 2003
    #6
  7. David Filmer

    Anno Siegel Guest

    David Filmer <> wrote in comp.lang.perl.misc:
    > 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
     
    Anno Siegel, Dec 11, 2003
    #7
  8. geoffroy <> wrote:

    > You can use this sub.



    I doubt that.


    > if($hashref->{'ssn'} eq $_[0]){retrun 1}

    ^^^^^^

    What does the retrun() function do?



    Have you seen the Posting Guidelines that are posted here frequently?


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Dec 14, 2003
    #8
  9. David Filmer

    geoffroy Guest

    David Filmer wrote:
    > 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
     
    geoffroy, Dec 14, 2003
    #9
    1. Advertisements

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. Steven Arnold

    using hashes as keys in hashes

    Steven Arnold, Nov 23, 2005, in forum: Ruby
    Replies:
    3
    Views:
    221
    Mauricio Fernández
    Nov 23, 2005
  2. kazaam
    Replies:
    12
    Views:
    358
    Matthias Wächter
    Sep 13, 2007
  3. Matt Brooks
    Replies:
    16
    Views:
    283
    Matt Brooks
    Sep 16, 2009
  4. Replies:
    12
    Views:
    229
    Dr.Ruud
    Oct 6, 2005
  5. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    290
Loading...

Share This Page