PDA

View Full Version : Storing an array in a hash


byuhobbes85
06-20-2008, 07:26 PM
I'm somewhat new to Perl, and very new to object-oriented programming in Perl. I've used OO programming extensively in Java and PHP, but I just have a question of how you would do something in Perl.

I have an object that I want to store, among other things, a list of filenames. The object is implemented as a hash, though, and I can see that you cannot store arrays in hashes. I tried storing a reference to the array in a scalar, but I am not sure what to do from here. Here is the code.

package BlastFactory;

# Constructor
sub new {
# Get parameters, set to an anonymous hash
my ($class, $filename) = @_;
return bless {
_query_files => load_query_files($filename)
}, $class;
}

# Load the query files into an array
sub load_query_files {
# Grab parameters
my ($file_to_load) = @_;
# Create an array to store query filenames
my @q_files = ();
# If the input file exists
if(-e $file_to_load) {
# ...load it
open INPUT, $file_to_load;
} else {
# Otherwise, die trying
die("ERROR: file '$file_to_load' does not exist");
}
# For each line of the input file...
while(<INPUT>) {
# ...grab the line
my $query_file = $_;
# Trim it
chomp($query_file);
# Add it to the array
push(@q_files, $query_file);
}
# Close the input streamm
close(INPUT);
# I have tested it here and the array is correct
return @q_files
}

# Count method...get number of query files
sub get_query_file_count {
my $count = @_[0]->{_query_files};
# When I call this method, however, it gives me the first value in the original array.
return $count;
}

# Success
1;

I've done a bit of testing so that I know the array is created correctly, but only the first value of the array is being stored in the object's hash. Does anyone have any tips? Thanks!

FishMonger
06-21-2008, 12:02 AM
First, every Perl script you write, including modules, should include the warnings and strict pragmas.

Your open call and while loop could be simplified and improved.

package BlastFactory;

use strict;
use warnings;

# Constructor
sub new {
# Get parameters
my ($class, $filename) = @_;

# initialize the hash ref
my $self = {};

# load the array
my @files = _load_query_files($filename);

# load the hash with a ref to the array
$self->{_query_files} = \@files;

return bless $self, $class;
}

# Load the query files into an array
sub _load_query_files {
# Grab parameters
my ($file_to_load) = @_;

# If the input file exists...load it
# use a lexical var for the filehandle and the 3 arg form of open
# as well as include the system error message why it failed
open my $FILE, '<', $file_to_load
or die "ERROR: failed to open '$file_to_load' $!";

# slup the file data into an array
chomp(my @q_files = <$FILE>);
# one advantage of the lexical filehandle is that
# it automatically closes when it goes out of scope

return @q_files;
}

# Count method...get number of query files
sub get_query_file_count {
return scalar @{$_[0]->{_query_files}};
}

# Success
1;

byuhobbes85
06-23-2008, 03:05 PM
Thanks for your input. It cleaned things up quite a bit.

I noticed you suggested I change my subroutine from load_query_files to _load_query_files. Additionally, a lot of examples I've seen store class variables with a leading underscore. Does this have any practical effect on the implementation, or is it simply a de facto convention used by programmers?

Thanks!

FishMonger
06-23-2008, 05:27 PM
The leading underscore does not have any effect on the operation of the module. It is used as a convention to indicate that the subroutine or variable is private to the module and is not meant to be accessed directly. They should only be accessed indirectly via methods within the module.

Here's an example of what is allowed but should not be done.

my $files = new BlastFactory('somefile');
my @files = $files->_load_query_files('anotherfile');