Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

get keys from array of hashes

by PerlSufi (Friar)
on Aug 01, 2014 at 21:15 UTC ( [id://1095961]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks,
SOLVED
I want to get the keys from an Array of Hashes and put them into an array ref for using as column names with Text::CSV. All of the keys will be the same so I just need the one hash's set of them. I even know how many there will be- but I want to know if there is a better way than this:
use strict; use warnings; use Text::CSV; my $csv = Text::CSV->new( { binary => 1, eol => "\n" } ); my $file = "records.csv"; open( my $csv_fh, '>', $file ) or die "Unable to open $file for writin +g: $!\n"; my $AoH_records = [ { foo => 'bar', key => 'value', }, ]; my $columns = []; for my $key ( keys @{$AoH_records}[0] ) { push @{$columns}, $key; last if scalar(@{$columns}) == 10; } $csv->column_names( $columns );

Any insight is greatly appreciated :)

Replies are listed 'Best First'.
Re: get keys from array of hashes
by roboticus (Chancellor) on Aug 01, 2014 at 21:42 UTC

    PerlSufi:

    I don't like the "last if scalar(@{$columns}) == 10" bit. Since the keys could come in with any order, you're basically getting 10 random keys. It'll work, and the values should come in the same order so I'm not worried about that. But how do you know you'll get the 10 keys you want? I'd suggest either whitelisting a set of keys or blacklisting a set rather than using an explicit count.

    Otherwise, it looks just fine. Though I'd just go ahead and make an array of columns instead of the array reference, as it would simplify the code a little:

    my @columns; for my $key ( keys @{$AoH_records}[0] ) { push @columns, $key; last if scalar @columns == 10; } $csv->column_names( @columns );

    (Though the array slice that AppleFritter mentions would be shorter still.)

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: get keys from array of hashes
by AppleFritter (Vicar) on Aug 01, 2014 at 21:27 UTC

    keys already returns a list, so you could directly assign that to an array and use splice to truncate it:

    my @columns = keys $AoH_records->[0]; splice @columns, 10; $csv->column_names(\@columns);

    If you don't care about truncating the array, you don't even need to save it, since ->column_names() will accept a list as well as an array reference:

    $csv->column_names(keys $AoH_records->[0]);

    BTW, on truncating arrays:

    • It's also possible to assign to $#columns to set it to a specific length, but unlike splice, this will pad it with new undefined elements if it's shorter.

    • The above splice call will produce a warning if the array has less than ten elements. To avoid that, do e.g. this:

      use List::Util qw/min/; # ... splice @columns, min 10, scalar @columns

      Thanks AppleFritter,
      Your method SHOULD work, but I am just now realizing that the  ->column_names method itself is not working for me- but using  ->print($csv_fh, $columns) does?
      UPDATE: This is what I did for me to get it work, I am not sure why the column_names method isn't working for me though..
      my $columns = [ keys $AoH_records->[0] ]; $csv->print( $csv_fh, $columns );

        You're welcome! *tips hat*

        What do you mean by "not working for me"? As far as I can tell, ->column_names() is not for printing column names to a CSV file; quoting Text::CSV's documentation:

        column_names

        Set the keys that will be used in the getline_hr () calls. If no keys (column names) are passed, it'll return the current setting.

        So I'd say ->print() is the way to go, yes.

Re: get keys from array of hashes
by Anonymous Monk on Aug 02, 2014 at 12:33 UTC

    Just a note: The syntax keys @{$AoH_records}[0] (that's keys on a hashref instead of a hash) has been available since v5.14 and is "highly experimental" (as documented at the bottom of keys), and as of v5.20 generates a warning "keys on reference is experimental". This is due in part to the fact that the experimental postfix dereference syntax is available as of v5.20, which may replace the "keys on reference" (autoderef) feature in the future (see perl5200delta).

    So alternatively you could write keys %{$AoH_records->[0]} to avoid the whole thing. Or, assuming the postderef syntax becomes standard, you can write use feature 'postderef'; and then keys $AoH_records->[0]->%*

      ...scratch that, I should've read your post. :P

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-24 19:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found