Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Hash table of arrays

by Grumpy (Initiate)
on Jul 05, 2000 at 21:36 UTC ( [id://21167]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, all. Pretty new at this, but I'm trying to build a hash table where the values are pointers to arrays. The code below is my pathetic attempt to say, "if the user is not already in the array indexed by that machine name, add him."

if (!grep (/.*$uname.*/, @{$machinearray{$machine}})) { ${$machinearray{$machine}}[$#{machinearray{$machine}}] = $pwline; }

The error I get is Can't use subscript on array length at ./gendist line 41, near "$machine}"

Incidentally, the second line is #41. Anyone who'd care to explain what I'm doing wrong will be my personal hero.

Replies are listed 'Best First'.
Re: Hash table of arrays
by btrott (Parson) on Jul 05, 2000 at 21:47 UTC
    I think what you're doing is looking up a particular user on a particular machine; and if that user doesn't exist on that machine, then you're adding that user to that machine list. Right? You should be using push to add the user to the array of users:
    push @{ $machinearray{$machine} }, $pwline;
    This will add $pwline to the end of the array.

    You may want to think about alternate data structures, though, if you're going to be looking up a lot of users. Something like this, perhaps?

    my %machines = ( machine1 => { user1 => 'pwline1', user2 => 'pwline2', }, machine2 => { user1 => 'pwline1', user3 => 'pwline3', }, );
    This way you can quickly look up a particular user on a particular machine, and you also have access to the password lines. Then you could do:
    if (!exists $machines{$machine}{$uname}) { ## User doesn't exist. Add him/her. $machines{$machine}{$uname} = $pwline; }
    Make sense?
Re: Hash table of arrays
by splinky (Hermit) on Jul 05, 2000 at 21:55 UTC
    Looks like you have an extra ${} in there. But I'll do you one better and show you an easier way.

    push @{$machinearray{$machine}}, $pwline;

    You can also tighten up your grep a bit. If $uname contained "brad", for example, and your array contained "bradford", it would match your regex and fail to add "brad" to the array. The following is probably what you want:

    if (!grep {$_ eq $uname} @{$machinearray{$machine}})



Re: Hash table of arrays
by davorg (Chancellor) on Jul 05, 2000 at 23:35 UTC

    I'd take a slightly different approach. If you stored your data as a hash of hashes, then the keys in the first hash could be the machine name and the values could be references to second level hashes. The key to these hashes would be the user names and the values would be an integer which is incremened each time to find a particular user on a particular machine.

    You could replace your code above with:


    which would automatically creat sub-hashes as required.

    As a bonus, you could easily find if a particular user is on a particular machine using

    if (exists $machinearray{$machine}{$user})

    and you could get a list of users on a particular machine using

    keys %{$machinearray{$machine}};

    European Perl Conference - Sept 22/24 2000, ICA, London
Re: Hash table of arrays
by ZZamboni (Curate) on Jul 06, 2000 at 00:01 UTC
    Apart from the other comments, using grep with user-supplied data as the pattern (as your $uname variable may be) is evil and should be avoided, because it opens the possibility to all sorts of mischief. What if $uname contains regular expression metacharacters? What if it contains one of the magic forms that allow you to execute arbitrary Perl code? I would also suggest using hashes for storing the user names. Makes your code a lot cleaner and makes it much easier to test whether a user is already there.

    For some related discussion, see the FAQ How can I tell whether a list or array contains a certain element?


Re: Hash table of arrays
by Buckaroo Buddha (Scribe) on Jul 05, 2000 at 21:42 UTC
Re: Hash table of arrays
by Anonymous Monk on Jul 06, 2000 at 02:08 UTC
    Thank you teachers and fellow seekers. I meditated on what you said here and I have come up with:

  • Push is good. I will remember it for the future.
  • I have scrapped the grepping of lists thing and am implementing it as a hash table of hash tables as Davorg suggested.
  • I don't understand Davorg's code, but mine works, even though I'm sure it's obviously written by a neophyte.

    Each response was thoughtful and informative. Thanks to you all.

Log In?

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-07-15 17:15 GMT
Find Nodes?
    Voting Booth?

    No recent polls found

    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.