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

Hi everyone. It is the second time I am using your help and I would like to thank you for the first one once again! Here is my problem. The code that you will find below opens a .csv file and parses it and returns a specific value. I want this function to not only return this value but also return the value in row 1 column A (the very first entry). I don't insist on this being done in the function so if you can help me figure out how to do it in a new, smaller function I would highly appreciate your help.
sub hlookup { my $csv_file = shift; my $field_name = shift; my $row_num = shift; my $csv = Text::CSV_XS->new ( { binary => 1 } ) # should set bin +ary attribute. or die "Cannot use CSV: ".Text::CSV->error_diag (); open my $fh, "<:encoding(utf8)", $csv_file or die "test.csv: $!"; my $field_num; my $first_row = $csv->getline_all( $fh ,3, 1 ); $csv->column_names(@$first_row); my $all = $csv->getline_hr_all($fh, $row_num - 2, 1); # - 2 since array indexes are 0-based, # and we count our lines 1-based, # and because we've already read the first # line. return $all->[0]->{$field_name} }
If I wasn't clear I just one to create (or add to this one) a function that returns the value in A1 from a .csv file.

Replies are listed 'Best First'.
Re: Parse .csv file
by kcott (Archbishop) on Jul 10, 2012 at 19:45 UTC

    You can return multiple results as:

    Array
    return ($all->[0]->{$field_name}, $first_cell);
    Arrayref
    return [$all->[0]->{$field_name}, $first_cell];
    Hashref
    return {field_name => $all->[0]->{$field_name}, first_cell => $first_cell};

    Of these, I'd pick one of the references as these package the data and you're only passing around a single scalar value. Further, I'd choose the hashref over the arrayref because you're not restricted to the order of the results and dealing with the returned values is easier and more readable. Consider:

    my $h = hlookup(...); # First cell value with arrayref my $first_cell = $h[1]; # First cell value with hashref my $first_cell = $h{first_cell};

    -- Ken

      Thank you both for your answers. My question is how do I get the value in cell A1 to be in $first_cell?

        Rather than trying to calculate a negative offset equating to the first record - and writing a multi-line comment explaining what you're doing - you can just reposition the file pointer to the start of the file with seek.

        In the code below, $called_first_row represents what you called $first_row. Perhaps $first_wanted_row, or something similar, would have been a better choice of variable name; $fourth_row would have been completely accurate.

        #!/usr/bin/env perl use 5.010; use strict; use warnings; use Text::CSV_XS; my $csv_file = q{pm_csv_first_cell.csv}; open my $csv_fh, q{<}, $csv_file or die $!; my $csv_obj = Text::CSV_XS::->new(); my $called_first_row = $csv_obj->getline_all($csv_fh, 3, 1); say qq{@{$called_first_row->[0]}}; seek $csv_fh, 0, 0; my $real_first_row = $csv_obj->getline_all($csv_fh, 0, 1); say qq{@{$real_first_row->[0]}}; say q{First cell value: }, $real_first_row->[0][0]; close $csv_file;

        Sample run and file contents:

        ken@ganymede: ~/tmp $ cat pm_csv_first_cell.csv z,x,c,v,b,n a,s,d,f,g,h q,w,e,r,t,y 1,2,3,4,5,6 ken@ganymede: ~/tmp $ pm_csv_first_cell.pl 1 2 3 4 5 6 z x c v b n First cell value: z ken@ganymede: ~/tmp $

        -- Ken

        After reading Text::CSV the following code can be suggested:
        my $a_one = $csv->getline($fh)->[0]; <...> my $first_row = $csv->getline_all( $fh ,2, 1 ); # decrease offset by 1 + because one line was read earlier
        Sorry if my advice was wrong.
Re: Parse .csv file
by frozenwithjoy (Priest) on Jul 10, 2012 at 19:48 UTC
    A simple way that is completely independent of this subroutine is to open the filehandle, capture the first line in a scalar, close filehandle, split on commas and capture the first element.

    edit: go with kcott's suggestion. It is much nicer.