I keep printing my hash as # of buckets / # allocated.
How do I print the contents of my hash?
Without using a while loop would be most preferable (for example, a one-liner would be best).
Data::Dumper is your friend.
use Data::Dumper;
my %hash = ('abc' => 123, 'def' => [4,5,6]);
print Dumper(\%hash);
will output
$VAR1 = {
'def' => [
4,
5,
6
],
'abc' => 123
};
Easy:
print "$_ $h{$_}\n" for (keys %h);
Elegant, but actually 30% slower (!):
while (my ($k,$v)=each %h){print "$k $v\n"}
Here how you can print without using Data::Dumper
print "#{[%hash]}";
For debugging purposes I will often use YAML.
use strict;
use warnings;
use YAML;
my %variable = ('abc' => 123, 'def' => [4,5,6]);
print "# %variable\n", Dump \%variable;
Results in:
# %variable
---
abc: 123
def:
- 4
- 5
- 6
Other times I will use Data::Dump. You don't need to set as many variables to get it to output it in a nice format than you do for Data::Dumper.
use Data::Dump = 'dump';
print dump(\%variable), "\n";
{ abc => 123, def => [4, 5, 6] }
More recently I have been using Data::Printer for debugging.
use Data::Printer;
p %variable;
{
abc 123,
def [
[0] 4,
[1] 5,
[2] 6
]
}
( Result can be much more colorful on a terminal )
Unlike the other examples I have shown here, this one is designed explicitly to be for display purposes only. Which shows up more easily if you dump out the structure of a tied variable or that of an object.
use strict;
use warnings;
use MTie::Hash;
use Data::Printer;
my $h = tie my %h, "Tie::StdHash";
#h{'a'..'d'}='A'..'D';
p %h;
print "\n";
p $h;
{
a "A",
b "B",
c "C",
d "D"
} (tied to Tie::StdHash)
Tie::StdHash {
public methods (9) : CLEAR, DELETE, EXISTS, FETCH, FIRSTKEY, NEXTKEY, SCALAR, STORE, TIEHASH
private methods (0)
internals: {
a "A",
b "B",
c "C",
d "D"
}
}
The answer depends on what is in your hash. If you have a simple hash a simple
print map { "$_ $h{$_}\n" } keys %h;
or
print "$_ $h{$_}\n" for keys %h;
will do, but if you have a hash that is populated with references you will something that can walk those references and produce a sensible output. This walking of the references is normally called serialization. There are many modules that implement different styles, some of the more popular ones are:
Data::Dumper
Data::Dump::Streamer
YAML::XS
JSON::XS
XML::Dumper
Due to the fact that Data::Dumper is part of the core Perl library, it is probably the most popular; however, some of the other modules have very good things to offer.
My favorite: Smart::Comments
use Smart::Comments;
# ...
### %hash
That's it.
Looping:
foreach(keys %my_hash) { print "$_ / $my_hash{$_}\n"; }
Functional
map {print "$_ / $my_hash{$_}\n"; } keys %my_hash;
But for sheer elegance, I'd have to choose wrang-wrang's. For my own code, I'd choose my foreach. Or tetro's Dumper use.
I really like to sort the keys in one liner code:
print "$_ => $my_hash{$_}\n" for (sort keys %my_hash);
If you want to be pedantic and keep it to one line (without use statements and shebang), then I'll sort of piggy back off of tetromino's answer and suggest:
print Dumper( { 'abc' => 123, 'def' => [4,5,6] } );
Not doing anything special other than using the anonymous hash to skip the temp variable ;)
The easiest way in my experiences is to just use Dumpvalue.
use Dumpvalue;
...
my %hash = { key => "value", foo => "bar" };
my $dumper = new DumpValue();
$dumper->dumpValue(\%hash);
Works like a charm and you don't have to worry about formatting the hash, as it outputs it like the Perl debugger does (great for debugging). Plus, Dumpvalue is included with the stock set of Perl modules, so you don't have to mess with CPAN if you're behind some kind of draconian proxy (like I am at work).
I append one space for every element of the hash to see it well:
print map {$_ . " "} %h, "\n";
Related
I have the following hash, and I wish to keep it in the order I've set it in; is this even possible? If not, do any alternatives exist?
my %hash = ('Key1' => 'Value1', 'Key2' => 'Value2', 'Key3' => 'Value3');
Do I need to write a custom sorting subroutine? What are my options?
Thank you!
http://metacpan.org/pod/Tie::IxHash
use Tie::IxHash;
my %hash;
tie %hash,'Tie::IxHash';
This hash will maintain its order.
See Tie::Hash::Indexed. Quoting its Synopsis:
use Tie::Hash::Indexed;
tie my %hash, 'Tie::Hash::Indexed';
%hash = ( I => 1, n => 2, d => 3, e => 4 );
$hash{x} = 5;
print keys %hash, "\n"; # prints 'Index'
print values %hash, "\n"; # prints '12345'
Try doing this :
print "$_=$hash{$_}\n" for sort keys %hash;
if you want it sorted in alphabetic order.
If you need to retain original order, see other posts.
See http://perldoc.perl.org/functions/sort.html
One possibility is to do the same as you sometimes do with arrays: specify the keys.
for (0..$#a) { # Sorted array keys
say $a[$_];
}
for (sort keys %h) { # Sorted hash keys
say $h{$_};
}
for (0, 1, 3) { # Sorted array keys
say $h{$_};
}
for (qw( Key1 Key2 Key3 )) { # Sorted hash keys
say $h{$_};
}
You can also fetch the ordered values as follows:
my #values = #h{qw( Key1 Key2 Key3 )};
This depends on how you're going to access the data. If you just want to store them and access the last/first values, you can always put hashes in an array and use push() and pop().
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10;
use Data::Dumper;
my #hashes;
foreach( 1..5 ){
push #hashes, { "key $_" => "foo" };
}
say Dumper(\#hashes);
I'm stuck on this problem for days and don't know which data structure I should use in Perl
Suppose I have this file with the following inputs:
lookup hello
lookup good night
good night
I want to be able to store "lookup" linked with "hello", "lookup" linked with "good night" and lastly "good night" linked with nothing else. Should I use a hash or an array? If I set "lookup" as the key of the hash, I will lose "hello" information. If I set "good night" as key, I will end up losing the 3rd line of information.
What should I do?
EDIT: There are certain keywords (which I called "lookup") that has stuff that are linked to them. For example, "password" will be followed by the actual password whereas "login" need not have anything following it.
It's not exactly clear how you're expecting to break up the words here, but in the general case, if you need to do random lookups (by arbitrary word), a hash is a better fit than an array. Without additional details on exactly what you're trying to do here, it's hard to be more specific.
It looks like you want a hash of arrays. Ignoring the issue of how to decide the key is "good night" instead of "good" (and just assuming the key should be "good"), you could do something like:
#!/usr/bin/env perl
use strict;
use warnings;
my %hoa; # hash of arrays
while(<>) {
my #f = split;
my $k = shift #f;
$hoa{ $k } = [] unless $hoa{ $k };
push #{$hoa{ $k }}, join( ' ', #f );
}
foreach my $k( keys( %hoa )) {
print "$k: $_\n" foreach ( #{$hoa{ $k }});
}
Not quite sure what you want, but, is this ok:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dump qw(dump);
# build a hash of keywords
my %kword = map{ $_ => 1}qw(lookup kword1 kword2);
my %result;
while(<DATA>) {
chomp;
my ($k, $v) = split(/ /,$_, 2);
push #{$result{$k}}, $v if exists $kword{$k};
}
dump%result;
__DATA__
lookup hello
lookup good night
good night
kword1 foo
kword1 bar
output:
("kword1", ["foo", "bar"], "lookup", ["hello", "good night"])
You could also use a hash of hashes if you plan to store another piece of data with your linked "lookup"->"good night" which will be easy to access later on.
E.g:
%result = (
'lookup' => {
'hello' => $storage1,
'good night' => $storage2,
},
'good night' => {
}
);
Is there a hash equivalent for map?
my %new_hash = hash_map { new_key($a) => new_val($b) } %hash;
I know that I could loop through the keys.
List::Pairwise claims to implement exactly that syntax -- see mapp, grepp. I haven't used it though.
Also, you can do it as
%new_hash = map { new_key($_) => new_value($hash{$_}) } keys %hash;
which I admit looks clumsier if %hash is really a $deeply->{buried}->{hash}. I prefer using $temp = ...; map {...} keys %$temp in such cases.
I really can’t see what you are trying to do here. What does “a hash equivalent for map” even mean? You can use map on a hash just fine. If you want the keys, just use keys; for example"
#msglist = map { "value of $_ is $hash{$_}" } keys %hash
although usually
say "value of $_ is $hash{$_}" keys %hash;
is just fine.
If you want both, then use the whole hash.
For assignment, what’s wrong with %new_hash = %old_hash?
Do you have deep-copy issues? Then use Storable::dclone.
Do you want both key and value available in the closure at the same time? Then make a bunch of pairs with the first map:
#pairlist = map { [ $_ => $hash{$_} ] } keys %hash
I need to see an example of what you would want to do with this, but so far I can see zero cause for using some big old module instead of basic Perl.
You can use map like this:
my $i = 0;
my %new_hash = map { $i ^= 1 ? new_key($_) : new_val($_) } %hash;
You can use mapn from my module List::Gen to do this:
use List::Gen 'mapn';
my %new_hash = mapn {new_key($_[0]) => new_value($_[1])} 2 => %old_hash;
mapn is like map, except it it takes an additional argument, the number of elements to walk the list by. Inside the block, the #_ array is set to the current slice.
$ perl -d /dev/null
DB<2> %p = ( a=>'b', c=> 'd');
DB<5> p Dumper \%p
$VAR1 = {
'c' => 'd',
'a' => 'b'
};
To e.g. reverse the key and the value:
DB<6> %q = map { ($p{$_}, $_ ) } keys %p
DB<7> p Dumper \%q
$VAR1 = {
'b' => 'a',
'd' => 'c'
};
As of perl 5.20, core utility List::Util::pairmap does exactly that:
use List::Util qw(pairmap);
my %new_hash = pairmap { new_key($a) => new_val($b) } %hash;
It's not necessarily optimal (as it involves unrolling the hash to a list and back) but I believe this is the shortest way in vanilla perl.
Is there an easy way to print out a Perl array with commas in between each element?
Writing a for loop to do it is pretty easy but not quite elegant....if that makes sense.
Just use join():
# assuming #array is your array:
print join(", ", #array);
You can use Data::Dump:
use Data::Dump qw(dump);
my #a = (1, [2, 3], {4 => 5});
dump(#a);
Produces:
"(1, [2, 3], { 4 => 5 })"
If you're coding for the kind of clarity that would be understood by someone who is just starting out with Perl, the traditional this construct says what it means, with a high degree of clarity and legibility:
$string = join ', ', #array;
print "$string\n";
This construct is documented in perldoc -fjoin.
However, I've always liked how simple $, makes it. The special variable $" is for interpolation, and the special variable $, is for lists. Combine either one with dynamic scope-constraining 'local' to avoid having ripple effects throughout the script:
use 5.012_002;
use strict;
use warnings;
my #array = qw/ 1 2 3 4 5 /;
{
local $" = ', ';
print "#array\n"; # Interpolation.
}
OR with $,:
use feature q(say);
use strict;
use warnings;
my #array = qw/ 1 2 3 4 5 /;
{
local $, = ', ';
say #array; # List
}
The special variables $, and $" are documented in perlvar. The local keyword, and how it can be used to constrain the effects of altering a global punctuation variable's value is probably best described in perlsub.
Enjoy!
Also, you may want to try Data::Dumper. Example:
use Data::Dumper;
# simple procedural interface
print Dumper($foo, $bar);
For inspection/debugging check the Data::Printer module. It is meant to do one thing and one thing only:
display Perl variables and objects on screen, properly formatted (to
be inspected by a human)
Example usage:
use Data::Printer;
p #array; # no need to pass references
The code above might output something like this (with colors!):
[
[0] "a",
[1] "b",
[2] undef,
[3] "c",
]
You can simply print it.
#a = qw(abc def hij);
print "#a";
You will got:
abc def hij
# better than Dumper --you're ready for the WWW....
use JSON::XS;
print encode_json \#some_array
Using Data::Dumper :
use strict;
use Data::Dumper;
my $GRANTstr = 'SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE, TRIGGER';
$GRANTstr =~ s/, /,/g;
my #GRANTs = split /,/ , $GRANTstr;
print Dumper(#GRANTs) . "===\n\n";
print Dumper(\#GRANTs) . "===\n\n";
print Data::Dumper->Dump([\#GRANTs], [qw(GRANTs)]);
Generates three different output styles:
$VAR1 = 'SELECT';
$VAR2 = 'INSERT';
$VAR3 = 'UPDATE';
$VAR4 = 'DELETE';
$VAR5 = 'LOCK TABLES';
$VAR6 = 'EXECUTE';
$VAR7 = 'TRIGGER';
===
$VAR1 = [
'SELECT',
'INSERT',
'UPDATE',
'DELETE',
'LOCK TABLES',
'EXECUTE',
'TRIGGER'
];
===
$GRANTs = [
'SELECT',
'INSERT',
'UPDATE',
'DELETE',
'LOCK TABLES',
'EXECUTE',
'TRIGGER'
];
This might not be what you're looking for, but here's something I did for an assignment:
$" = ", ";
print "#ArrayName\n";
Map can also be used, but sometimes hard to read when you have lots of things going on.
map{ print "element $_\n" } #array;
I've not tried to run below, though. I think this's a tricky way.
map{print $_;} #array;
I have a problem to write and read properly a CSV file composed of name(key) and array of values:
testarray.csv
foo1 ,0,0,0,0,1
foo2 ,1,0,0,0,1
foo3 ,3,4,5,6,7
.
.
.
I need to represent that file as follows:
foo# will be the key and the five following numbers will be its array.
What is the simple way to conduct that and to recall it for a use (not with Dumper)? How can I use a varible from an array of a specific key?
E.g.,
print $hsh{'foo1'}[4];
Normally, I would recommend Text::xSV and/or Text::CSV but for such simple data, a straightforward join should work:
#!/usr/bin/perl
use strict;
use warnings;
my %hash = (
foo1 => [ 0, 0, 0, 0, 1 ],
foo2 => [ 1, 0, 0, 0, 1 ],
foo3 => [ 3, 4, 5, 6, 7 ],
);
for my $key ( sort keys %hash ) {
print join( q{,}, $key, #{ $hash{$key} } ), "\n";
}
__END__
Output:
C:\Temp> ttt
foo1,0,0,0,0,1
foo2,1,0,0,0,1
foo3,3,4,5,6,7
Reading it in:
#!/usr/bin/perl
use strict;
use warnings;
my %hash;
while ( <DATA> ) {
chomp;
last unless /\S/;
my ($key, #data) = split /,/;
$hash{$key} = \#data;
}
print $hash{foo2}->[4], "\n";
__DATA__
foo1,0,0,0,0,1
foo2,1,0,0,0,1
foo3,3,4,5,6,7
Output:
C:\Temp> ttt
1
Sinan Unur's solution is good and correct, but I think that the OP's problem is an XY Problem. He is specifically asking about reading and storing data from a CSV file. Since that seems to be the real goal, then the best solution is to make use of reuse and get Text::CSV installed in your Perl. It does the heavy lifting of dealing with CSV files, gives you ways to reference all the data, and provides a nice API while doing so.
If that doesn't float your boat, you can try DBD::CSV which, in conjunction with DBI will give you the ability to use SQL to query/insert/update the CSV. If you're used to SQL, that is a nifty way to proceed as well.
Edit:
Based on simple nature of data, if you really want to roll your own, his solution is a good one, already gave it +1.