4

If I have the following array

my @header_line = ('id', 'name', 'age');

How do I create a hash from it equivalent to the line below?

my %fields = { id => 0, name => 1, age => 2};

The reason I want to do this is so that I can use meaningful names rather than magic numbers for indexes. For example:

$row->[$fields{age}]; # rather than $row->[2] 
4
  • why not change $row to %row (a hash)? Commented Nov 11, 2010 at 16:13
  • 1
    It comes from Text::CSV e.g., my $row = $csv->getline($fh) Commented Nov 11, 2010 at 16:18
  • 2
    Since you have @header_line, you can turn $row to a hash quite easily: my %row_hash = map { $_ => shift @{$row} } @header_line;. Just another alternative, but might be cleaner using $row_hash{age} than having to use the $row->[$fields{age}] notation... Commented Nov 11, 2010 at 17:54
  • Since you have @header_line, you can turn $row to a hash quite easily: my %row_hash; @row_hash{@header_line} = @{$row};. I had to think a second about how your code worked, and a hash slice is much cleaner. Commented Nov 12, 2010 at 17:52

5 Answers 5

15
my %fields;
@fields{@header_line} = (0 .. $#header_line);
Sign up to request clarification or add additional context in comments.

2 Comments

@swisstony: It just came to my mind, if your indexes are known statically, constants would be more convenient. use constant { id => 0, name => 1, age => 2}; print $row->[age];
I see, but then I would have to maintain two data structures. I already have an array called header_line, which is used when printing column names ($csv->print( $fh, get_header_line();). I would also have to maintain a separate hash for the indexes. I should say I actually have about 40 column names in header_line not the 3 as in my example. I suppose it would work if I could create the header_line as a ref to an array from the hash, which is what Text::CSV wants, but I'm not sure how to that.
6
my %fields = map { $header_line[$_] => $_ } 0..$#header_line;

Comments

3

You said in reply to a comment that this is coming from Text::CSV. This module has a way to import this into a hash for you.

$csv->column_names( @header_line );
$row = $csv->getline_hr( $FH );
print $row->{ 'id' };

3 Comments

Didn't know about column_names and getline_hr - they were added in 2008, so relatively recent (in terms of Text::CSV). Makes the code much tidier...
I nearly got this working. The problem is $csv_o->print( $fh_o, $row ); fails because it expects an array ref. How do I write out the hash ref using the csv_o object? BTW, my script reads in one CSV, adds some fields, changes all column names (@header_line is new col names), and then writes out a new CSV file. I hadn't appreciate what I needed may be right under my nose. Very many thanks for your comment!
I've raised this as a new question as quite different to this one: stackoverflow.com/questions/4163048/…
1
my %fields = ();
for (my $i = 0; $i < scalar(@header_line); $i++) {
   $fields{$header_line[$i]} = $i;
}

Comments

0

TIMTOWTDI

my %fields = ();
foreach my $field(@header_line)
{
  $fields{$field} = scalar(keys(%fields));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.