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

I have a database made up of .dat files that are formatted as follows:

UserID001|username1|password1|displayname1| UserID002|username2|password2|displayname2| UserID003|username3|password3|displayname3| ...

This is only one record of the database, and many other records will be formatted in this same fashion but with varying numbers of columns. I am trying to write a subroutine to accept each record as an array, then return a hash for each column using the UserIDs as the hash keys.

I'm assuming it will be best to return references to these hashes, but I'm not sure how to dynamicly create a hash for each column. Here's what I have so far:

# Calling the subroutine ($usernamesRef,$passwordsRef,$displaynamesRef) = arrayToMultiHash (\@u +sers); %usernames = %{$usernamesRef}; %passwords = %{$passwordsRef}; %displaynames = %{$displaynamesRef}; # The subroutine sub arrayToMultiHash { my @array = @{$_[0]}; my @hashRefs; foreach $line (@array) { my @lineInfo = split (/\|/,$line); my $key = shift (@lineInfo); my $i = 0; foreach $value (@lineInfo) { my $hashName = "hash$i"; $hashName{$key} = $value; $i++; } } foreach (0..$i) { my $hashName = "hash$i"; push (@hashRefs,\%{$hashName}); } return (@hashRefs); }

Any help will be greatly appreciated. Thank you in advance.

Replies are listed 'Best First'.
Re: Creating dynamic hash names
by Gangabass (Vicar) on Sep 24, 2009 at 11:57 UTC

    Always start your programs like this:

    use strict; use warnings;

    Your $i variable is not defined. Also you need something like:

    $users{$key} = { username => $username, password => $password, displayname => $display_name, };
Re: Creating dynamic hash names
by Bloodnok (Vicar) on Sep 24, 2009 at 11:50 UTC
    Something along the lines of ...
    use warnings; use strict; use Data::Dumper; use Text::xSV; my $sv = Text::xSV->new(sep => '|', fh => *DATA); my $res = {}; while (my $row = $sv->get_row()) { $res->{shift @$row} = [ @$row ]; } print Dumper $res; __DATA__ UserID001|username1|password1|displayname1| UserID002|username2|password2|displayname2| UserID003|username3|password3|displayname3|
    when run, gives
    $ perl tst.pl $VAR1 = { 'UserID001' => [ 'UserID001', 'username1', 'password1', 'displayname1', undef ], 'UserID002' => [ 'UserID002', 'username2', 'password2', 'displayname2', undef ], 'UserID003' => [ 'UserID003', 'username3', 'password3', 'displayname3', undef ] };
    Is that the sort of thing you're after (with a bit of fettling to suit your individual needs) ??

    A user level that continues to overstate my experience :-))
Re: Creating dynamic hash names
by biohisham (Priest) on Sep 24, 2009 at 11:52 UTC

    Extend on this principle,if you know beforehand the variables for each column it'd be easier to implement.
    This code treats the first entry in the database row as the key which when incorporated into a hash would serve to represent an anonymous array of the rest of the line in that entry, this array would be the value for that key.
    use strict; use warnings; my %database; my ($id,$user,$password,$display); while(<DATA>){ chomp; ($id,$user,$password,$display)=split /\|/; $database{$id}=[] unless exists $database{$id}; #avoid prim +ary key duplications. push @{$database{$id}}, ($user, $password,$display); } foreach my $id (sort keys %database){ print "ID $id:\nINFO: @{$database{$id}}\n"; print "\n"; } __DATA__ UserID001|username1|password1|displayname1| UserID002|username2|password2|displayname2| UserID003|username3|password3|displayname3|
    #OUTPUT: ID UserID001: INFO: username1 password1 displayname1 ID UserID002: INFO: username2 password2 displayname2 ID UserID003: INFO: username3 password3 displayname3

    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.
Re: Creating dynamic hash names
by leocharre (Priest) on Sep 24, 2009 at 14:39 UTC
    I would suggest it's time to look into object oriented programming.
Re: Creating dynamic hash names
by Anonymous Monk on Sep 24, 2009 at 14:41 UTC
Re: Creating dynamic hash names
by Lamont85 (Novice) on Sep 24, 2009 at 12:49 UTC

    The number of variables for each column will change from record to record.

    This sample script tries to demonstrate what I am trying to do. Keep in mind, I am not an experienced Perl scripter and am trying to keep this simple.

    #!C:\Perl\bin\perl.exe use Strict; use Warnings; @users = ( "UserID001|user1|password1|Fred|", "UserID002|user2|password2|George|", "UserID003|user3|password3|Mike|"); @admin = ( "AdminID001|admin1|password1|Joe|1|", "AdminID002|admin2|password2|Frank|1|", "AdminID003|admin3|password3|Carl|2|"); ($usernamesRef ,$passwordsRef ,$displaynamesRef) = arrayToMultiHash (\@users); # @users contains 3 columns besides Use +rID %usernames = %{$usernamesRef}; %passwords = %{$passwordsRef}; %displaynames = %{$displaynamesRef}; ($adminUsernamesRef ,$adminPasswordsRef ,$adminDisplaynamesRef ,$adminAccessLevelsRef) = arrayToMultiHash (\@admin); # @admin contains 4 columns besides Adm +inID %adminUsernames = %{$adminUsernamesRef}; %adminPasswords = %{$adminPasswordsRef}; %adminDisplaynames = %{$adminDisplaynamesRef}; %adminAccessLevels = %{$adminAccessLevelsRef}; print "User: $displaynames{'UserID002'} | $usernames{'UserID002'}\n"; print "Admin: $adminDisplaynames{'AdminID002'} | $adminUsernames{'Admi +nID002'}; sub arrayToMultiHash { my @array = @{$_[0]}; my @hashRefs; foreach $line (@array) { my @lineInfo = split (/\|/,$line); my $key = shift (@lineInfo); my $i = 0; foreach $value (@lineInfo) { my $hashName = "hash$i"; $hashName{$key} = $value; $i++; } } foreach (0..$i) { my $hashName = "hash$i"; push (@hashRefs,\%{$hashName}); } return (@hashRefs); }

    Should print:

    User: George | user2
    Admin: Frank | admin2