Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Joining the hash values of an array of hashes

by Rodster001 (Pilgrim)
on May 16, 2015 at 00:04 UTC ( [id://1126830]=perlquestion: print w/replies, xml ) Need Help??

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

I can do it with multi lines (below). But I'd really like to do it in one, without the foreach ($names is an arrayref of hashes):
my @ids; foreach my $a (@{ $names }) { push(@ids,$a->{id}); } my $ids = join(",", @ids);
Thanks!

Replies are listed 'Best First'.
Re: Joining the hash values of an array of hashes
by NetWallah (Canon) on May 16, 2015 at 00:27 UTC
    'map' is your friend.
    my $ids = join ",", ( my @ids = map { $_->{id} } @$names );
    (The parens are optional, but allow for visual separation)

            "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Re: Joining the hash values of an array of hashes
by Athanasius (Archbishop) on May 16, 2015 at 04:28 UTC

    Hello Rodster001,

    Consider the following test data:

    This shows two ways in which you may get an undefined value: if the key id exists but the value is undef; and if the key is missing. In both cases, your multi-line code will insert an undef into @ids, which is almost certainly not what you want. (Ok, you may know that your data doesn’t contain any cases like these. But can you be sure that it never will? Defensive programming tests for corner cases and handles them gracefully.) Fix by testing for definedness:

    foreach my $a (@{ $names }) { push(@ids, $a->{id} // ()); }

    or, using map as per NetWallah++:

    my $ids = join ',', map { $_->{id} // () } @$names;

    See perlop#Logical-Defined-Or.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Joining the hash values of an array of hashes
by Laurent_R (Canon) on May 16, 2015 at 09:21 UTC
    Rodster001 : ($names is an arrayref of hashes)
    I guess you mean an arrayref of hashrefs.
    I'd really like to do it in one (line), without the foreach
    Why without the foreach? you can do in in one line with a foreach and without having to use an intermediate temporary array. For example:
    my $id = ""; $id .= "$_->{id}, " foreach @$names;
    Note that I have added a space after the comma because I find it visually better when printing it; just remove that space if you don't want it.

    Having said that about foreach, I must say that I would rather use a map for this problem:

    my $id = join ", ", map $_->{id}, @$names;
    or, taking into account Athanasius's judicious comment:
    my $id = join ", ", map $_->{id} // (), @$names;
    Also note that I have used for the map a syntax different from that used by the previous monks, this is just just for the sake of illustrating this alternate syntax.

    Je suis Charlie.
Re: Joining the hash values of an array of hashes
by sundialsvc4 (Abbot) on May 18, 2015 at 13:12 UTC

    All of the foregoing are very sage comments.   Consider them well.

    To the above I would stress:   “so what?” how many lines-of-code it does or doesn’t take?   It is likely to make precious-little difference in what the runtime engine actually does, but it will make your code less easy to read (therefore, for others to maintain), and, as noted above, it might conceal some pretty serious bugs.   When given a choice between “clever” and “clear,” choose clear.   (Paradoxically, your code might actually run faster.)

    Eventually, your “cleverness” will have to be changed, by someone else.   (You shouldn’t have been standing so close to the curb when that bread-truck went by ...)   Business requirements may change, or the addition of some new piece will necessitate changes to the old.   Now, your successor is obliged to, first, “reverse-engineer” what you did, instead of comprehending it instantly, and s/he must devise replacement code, not only for what s/he wants to add, but also to substitute for what the old (obfuscatory ...) code did.   And, to somehow test both.   The return-on-investment disappears pretty fast, if ever it existed at all.   Just do whatever need be done, in the most obvious and “future-proof” way you can muster, test it and move on.

Log In?
Username:
Password:

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

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

    No recent polls found