Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Mapping to an associative hash

by THRAK (Monk)
on Sep 16, 2003 at 20:57 UTC ( #291963=perlquestion: print w/replies, xml ) Need Help??

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

I have a tab delimited file that is a DB export of an addressbook. I want to map the data from this file into a hash that has associative keys. I can read the data into an array with no problem, but is there an easy way to map this into the hash? Or is there a way to split things into the hash instead of an array? I believe going from the array to a hash isn't too difficult, but I need to get to an associative hash. Maybe array -> hash -> associative hash? Don't know, that's why I'm posting this!

/usr/bin/perl -w use strict; my $import_file = shift || 'addresses'; my @tmp; my %import_data =( 'id' => '', 'username' => '', 'domain' => '', 'address' => '', 'firstname' => '', 'lastname' => '', 'nickname' => '', 'type' => '', 'street' => '', 'city' => '', 'state' => '', 'zip' => '', 'country' => '', 'company' => '', 'home_phone' => '', 'work_phone' => '', 'pager' => '', 'cellular' => '', 'fax' => '', 'other' => '', 'birth_month' => '', 'birth_day' => '', 'birth_year' => '', 'birthday' => 'undef', 'title' => '', 'status' => '', 'time_stamp' => '', 'middleinitial' => '', 'nameprefix' => 'undef', 'namesuffix' => 'undef', 'street2' => '', 'website' => '', 'notes' => '', 'department' => 'undef', 'assistant' => 'undef', 'dstreet' => '', 'dstreet2' => '', 'dcity' => '', 'dstate' => '', 'dzip' => '', 'dcountry' => '', 'dphone1' => 'undef', 'dphone2' => 'undef', 'daddress' => '', 'dspouse' => 'undef', 'danniversary_day' => '', 'danniversary_month' => '', 'dnotes' => 'undef', 'dwebsite' => '', 'daddress2' => '', 'danniversary_year' => '', 'category' => '', 'prime_phone' => '', ); open(FILE, "< $import_file") or die "Cannot open $import_file ERR: $!\ +n"; while (<FILE>) { @tmp = split /\t/; #map @tmp to %import_data here #then call a sub-routine to manipulate } close FILE;

Thank You,

-THRAK
www.polarlava.com

janitored by ybiC: <readmore> tags around long codeblock, as per Monastery convention

Replies are listed 'Best First'.
Re: Mapping to an associative hash
by Thelonius (Priest) on Sep 16, 2003 at 21:06 UTC
    Sure thing! If you have the keys you want in an array @keys (in the order that the data appears in the file), then all you need to say is:
    while (<FILE>) { my %data; chomp; @data{@keys} = split /\t/; # then call subroutine }
Re: Mapping to an associative hash
by Zaxo (Archbishop) on Sep 16, 2003 at 21:21 UTC

    You can use your knowlege of the keys/column names to make the file an array of hashes or, if there can be constructed a 'primary key' from the data, a hash of hashes. Assuming that the 'id' is unique, it might serve. In any case, make a constant array of your column names and fill in a hash slice over that with the data.

    Here is yet another way, making a hash of hashes on id, with the second level hashes constructed directly from a list,

    my @keys = qw( id username domain address); # and so on my %addressbook; while (<>) { # or whatever handle my @data = split /\t/; $addressbook{$data[0]} = { map { ($keys[$_] => $data[$_]) } 1..$#keys }; }
    There are lots of ways to do this.

    After Compline,
    Zaxo

Re: Mapping to an associative hash
by IOrdy (Friar) on Sep 17, 2003 at 01:56 UTC
    You could use DBD::CSV and supply the column names when you create the db handle. Then just $sth->fetchrow_hashref like you would any other sql query result.

    update: added some code :)
    my $dbh = DBI->connect(q{DBI:CSV:}); $dbh->{'csv_tables'}->{'mytable'} = { 'file' => 'mytable.csv', 'sep_char' => "\t" 'col_names' => ["col_a", "col_b", "col_c"] }; my $sth = $dbh->prepare("SELECT m.col_a, m.col_c FROM mytable m"); $sth->execute; my @rows; while (my $row = $sth->fetchrow_hashref) { push @rows, $row; }
Re: Mapping to an associative hash
by shenme (Priest) on Sep 16, 2003 at 21:20 UTC
    Your records have tab-delimited fields, so "@tmp = split /\t/;" copies those fields, in order, into the array.   Are the fields named in the same order you show in %import_data, that is, is the 'id' value first, then the 'username' value, and so on?   You just need to stuff name/value pairs into your hash using names in the same order as your values.

    my @field_names = qw( id username domain .... prime_phones ); my @field_values = split /\t/; @input_data{@field_names} = @field_values;
    That's using a "hash slice".   A longer parallel version (untested)
    my @field_names = qw( id username domain .... prime_phones ); my @field_values = split /\t/; for( my $i=0; $i<@field_values; ++$i ) { $input_data{$field_names[$i]} = $field_values[$i]; }
Re: Mapping to an associative hash
by CountZero (Bishop) on Sep 17, 2003 at 06:02 UTC

    IOrdy's comment made me think of the following: if the data is an export of a database, can't you directly access the database through some of the DBI::DBD combo's?

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      Your logic is correct, but this is part of a migration project and I don't have access to the database from which the data is coming. This is being supplied by a third-party as tab delimited files.

      -THRAK
      www.polarlava.com
Re: Mapping to an associative hash
by CountZero (Bishop) on Sep 16, 2003 at 21:25 UTC

    Is perhaps a "hash of hashes" what you are looking for? I.e. you have a top-level hash which is keyed by the ID-number and which refers to another hash which has all the keys you mention.

    If that fits your idea, have a look at perldoc perldsc which will explain it in full detail.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Mapping to an associative hash
by dragonchild (Archbishop) on Sep 16, 2003 at 21:10 UTC
    hashes are also known as associative ararys. hashing, by its nature, is associative. So, "associative hash" is redundant.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://291963]
Approved by Thelonius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (1)
As of 2023-03-25 10:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which type of climate do you prefer to live in?






    Results (63 votes). Check out past polls.

    Notices?