Re: A brain twister? (how to make 2 lines->1)
by muba (Priest) on Jun 25, 2012 at 02:08 UTC
|
use strict;
use warnings;
my %ahash=(one=>1, two=>2, three=>3, foo=>'$foo');
print join(", ",
map { "'$_' => '$ahash{$_}'"} keys %ahash
), "\n";
__END__
'three' => '3', 'one' => '1', 'foo' => '$foo', 'two' => '2'
Why are array so much easier to print out than hashes...geez...
I beg to differ. Just remember to read elements in pairs.
use strict;
use warnings;
my %ahash=(one=>1, two=>2, three=>3);
print join(", ", %ahash);
__END__
three, 3, one, 1, two, 2
| [reply] [d/l] [select] |
Re: A brain twister? (how to make 2 lines->1)
by roboticus (Chancellor) on Jun 25, 2012 at 02:14 UTC
|
perl-diddler:
If you don't have arrays & hashes in your hash, then a simple map might help:
print "{", join(", ", map { "$_=>$ahash{$}" } keys %ahash), "}\n";
...roboticus
When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] [select] |
|
|
@array=each %hash;,
#and
@array= [each %hash];...
but never got it to do what I wanted...sigh.
I've used map with values before, but was thinking there should be some way to do similar with 'each'...but each is just demented...1 item at a time...w/no slurp-ability......
And there I am with a straw trying to make it work...
| [reply] [d/l] |
|
|
but map only works on array according to the manpage
No, map works on lists.
but each is just demented...1 item at a time...w/no slurp-ability
No, each fills a specific, useful niche. You are forgetting that a hash in list context returns its keys and values:
@array=%hash;
Dave. | [reply] [d/l] |
|
|
while (my ($key, $value) = each %hash) {...}
See each for details. The example is directly from the documentation.
| [reply] [d/l] |
Re: A brain twister? (how to make 2 lines->1)
by AnomalousMonk (Archbishop) on Jun 25, 2012 at 03:51 UTC
|
>perl -wMstrict -le
"use Data::Dump qw(pp);
;;
my %hash = (one => 1, two => 2, foo => [ 99, { tres => 3 } ]);
;;
printf qq{%s \n}, pp \%hash;
"
{ foo => [99, { tres => 3 }], one => 1, two => 2 }
| [reply] [d/l] |
Re: A brain twister? (how to make 2 lines->1)
by tobyink (Canon) on Jun 25, 2012 at 06:43 UTC
|
use 5.014;
use Data::Dumper;
sub announce {
say Data::Dumper->new(\@_)->Indent(0)->Sortkeys(0)->Terse(1)->Dump;
}
my %ahash = (one=>1, two=>2, three=>3);
announce \%ahash;
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
| [reply] [d/l] |
Re: A brain twister? (how to make 2 lines->1)
by kcott (Archbishop) on Jun 25, 2012 at 07:04 UTC
|
$ perl -Mstrict -Mwarnings -E 'my %y = qw{c 3 d 4}; say "@{[%y]}";'
c 3 d 4
The expression can be arbitrarily complex.
$ perl -Mstrict -Mwarnings -E 'my %y = qw{c 3 d 4};
> say "@{[join q{;} => map { $_ . q{=} . $y{$_} } sort { $b cmp $a } k
+eys %y]}";'
d=4;c=3
You can use a subroutine.
$ perl -Mstrict -Mwarnings -E 'sub z { reverse @_ } my %y = qw{c 3 d 4
+};
> say "@{[z(%y)]}";'
4 d 3 c
| [reply] [d/l] [select] |
|
|
Well, not that I need the whole problem solved, but it was important to me to be able to print the hashes in hash format -- meaning they'll be bracketed with {} and have => between key/values, a strictly comma separated list defeats the purposes.
maybe using an embedded foreach w/each, since it seems like most of the above solutions lose the *visual* pairing.
(I also print out arrays in x, y, z form, and just wanted my hashes to look hashy!...
then again maybe just looping through using map & keys might
be sufficient...only 400 ways to do this, just finding the 'right' one...that generates the correct output... ;-)
| [reply] |
Re: A brain twister? (how to make 2 lines->1)
by MidLifeXis (Monsignor) on Jun 25, 2012 at 13:29 UTC
|
When I find myself being too clever (or find that I have been too clever in a previous version of code), I try to simplify it. If I don't, I find myself spending way too much time trying to understand the clever code I wrote yesterday (or last week / month / year), and wanting to go back and smack some sense into myself.
push @{$outp}, sprintf '"%s"=>"%s"', @$_ foreach
@{&{ sub ($) { my $_=["",[]];
push @{$_->[1]},\@{$_->[0]} while @{$_->[0]=[each $_[0]]};
$_->[1] } } (\%ahash)}, @{$v};
There is a lot packed into that code example that could probably be made more understandable, at the very least, with some whitespace.
push @{$outp},
sprintf '"%s"=>"%s"', @$_
foreach @{&{
sub ($) {
my $_=["",[]];
push @{$_->[1]}, \@{$_->[0]}
while @{$_->[0]=[each $_[0]]};
$_->[1]
}
} (\%ahash)},
@{$v};
although, in this case, I would probably give it some more care and feeding than just whitespace. Specifically (assuming that I am understanding what you are attempting to do), I would look at using map (map { sprintf... } along with keys instead of the foreach structure that you have.
Assuming that I am understanding your intent (which I still may not have grokked), does this do what you are attempting?
push @{$outp},
(
map {
sprintf '"%s"=>"%s"', $_, $ahash{$_};
} keys $ahash,
),
@{$v};
Just my $0.02
| [reply] [d/l] [select] |
|
|
Your code generates correct output! (minus the @{$v} --
not sure how that got there...doesn't make any sense).
And that may be the best solution I'm gonna be able to come up with for now..., but it isn't near as simple as 'join' for arrays... though I'm all but certain that the map is a better choice than the while loop.
I was really wanting 'each' in place of keys, and in a list of lists context, it would generate something along the lines of ((k, v),(k2,v2)...), that I could then feed to map, and map would pull off one pair/
usage.
Not saying it is possible, but for the work of the 'keys', an each doing the same would be of the same order as having an each that 'streams' kv pairs. --
I wanted to avoid the 2nd hash lookup ($ahash{$_}), as that makes the algorithm more like O(n^1.5), where keys and a streaming each would be of O(n).
The 'keys' has already done the work of looping through the entire hash and thrown away the values part - which is regenerated by the $ahash{$_}... and was just trying to find a way to avoid that waste if it was possible.... a bit "arcane", but....it was a hope....
I think my original solution might be closer to O(1), but the overhead of the while v. map would drown out any benefits even if it could be coerced into the right output...(order independent)...
{"three"=>"3", "one"=>"1", "two"=>"2"}
| [reply] [d/l] |
|
|
Hash lookups, if done right, are O(1) algorithms (see hash_table - thanks Ransom and possibly perldata (unverified) - thanks moritz). Since you are just looping through the list of keys (O(n)), looking up the hash table entry for that key (O(1)), and generating a string from the two values (O(1)), the order of the map should be O(n)*.
Performance is another issue entirely, but unless you are profiling the two implementations, and the speed performance boost is appreciable and worth the additional complexity, go with the implementation that is simpler to understand.
* - assuming that I am remembering my undergrad coursework properly.
Update: used performance instead of speed since you may not be optimizing for speed, but some other metric.
| [reply] |
|
|