Re: Stringified hash
by dragonchild (Archbishop) on Apr 12, 2004 at 12:16 UTC
|
use strict;
use warnings;
my %hash = ( A => 'a',
B => 'b',
C => 'c',
D => 'd',
E => 'e',
F => 'f' );
my @x = %hash;
print "@x\n";
Basically, you're imposing list context on the hash, which gives you back the key-value pairs (in semi-random order). The @{[ ... ]} construct is a way of imposing list context within an interpolating string. *shrugs* Neat corner case. :-)
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] [d/l] [select] |
Re: Stringified hash
by liz (Monsignor) on Apr 12, 2004 at 12:21 UTC
|
%hash # flatten hash to key/value pairs
[%hash] # create anonymous list reference to flattened hash
@{[%hash]} # dereference anonymous array reference
"@{[%hash]}" # interpolate in double quoted string (with $" inbet
+ween)
Hope this helps.
Liz | [reply] [d/l] |
Re: Stringified hash
by Roger (Parson) on Apr 12, 2004 at 12:20 UTC
|
In the code @{[ %hash ]}:
[ ... ] creates an anonymous list reference (from the given hash). And @{ ... } dereferences the anonymous list reference. And then the double quotes interpolate the elements with spaces.
| [reply] [d/l] [select] |
|
|
an anonymous list reference
That's an array reference, not a list reference. Run perldoc -q "difference between" (or check out perldoc.com's version) for a discussion on the difference. I'm sorry to be such a terminology nazi, but this is quickly becoming a pet-peeve of mine. :-)
| [reply] [d/l] |
|
|
Thanks for the correction. :-)
| [reply] |
Re: Stringified hash
by Anonymous Monk on Apr 12, 2004 at 12:26 UTC
|
Great! Thanks all!
The script is actually creating a dB query something like this. The code worked but I wasn't totally sure how.
Thanks again.
use strict;
use warnings;
my %hash = ( A => 'a',
B => 'b',
C => 'c',
D => 'd',
E => 'e',
F => 'f' );
print "@{[%hash]}";
while(my ($key, $value) = each(%hash)) {
$hash{$key} = '= '.$value.' AND';
}
my $query = 'SELECT row_id FROM Table WHERE '.substr("@{[%hash]}",0,-4
+);
print "\n\n$query\n";
| [reply] [d/l] |
|
|
You'll want to rewrite that code, so that it's not obfuscated.
my @clauses;
my @params;
while (my ($k, $v) = each %hash)
{
push @clauses, "$k = ?";
push @params, $v;
}
my $query = "SELECT row_id FROM Table WHERE " . join(" AND ", @clauses
+);
Then, when you execute that query using DBI, you pass @params to the execute() call. This will close a few security holes you currently have, as well as a few potential bugs. And, it's easier to read. :-)
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] [d/l] [select] |
|
|
This way worked out nicely for me. I guess I immediately thought of hash when an array would do. I'm not too worried about security. There is no interface, I'm processing files and loading them into a dB and I'm using ODBC. Thanks for the hand.
use strict;
use warnings;
my @array = ( "A = 'a'",
"B = 'b'",
"C = 'c'",
"D = 'd'",
"E = 'e'",
"F = 'f'" );
print "@array\n";
my $query = 'SELECT row_id FROM Table WHERE '.join(' AND ', @array);
print "\n\n$query\n";
| [reply] [d/l] |
|
|
|
|
See, I personally find this much easier to read, but I tend to find each loops generally hard to read. (I recognize that they're sometimes necessary for efficiency reasons, but still consider them ugly) Maybe it's just me.
my @fields = keys(%hash);
my @params = @hash{@fields};
my $query = "SELECT row_id FROM Table WHERE " .
join(" AND ", map {"$_ = ?"} @fields);
If for some reason the interface you have won't accomodate the extra separate @params parameter, you could also do this, though this depends on having the DBI handle available when you're forming the query:
my @fields = keys(%hash);
my $query = "SELECT row_id FROM Table WHERE " .
join(" AND ",
map {"$_ = " . $dbh->quote($hash{$_})} @fields);
However, I'd still go with the first, assuming that passing along the @params list is doable. | [reply] [d/l] [select] |