idiom for filling a counting hash
I use over and over this idiom in perl5: $a{$_}++ for @a; This is nice and perlish but it gets easily pretty boring when dealing with many list/arrays and counting hashes. I thought overloading the += operator %a += @a; Probably that operator should be smart enough to be fed with a mixed list of array and hashes as well: %a += ( @a, %h); # would mean %a += ( @a, keys %h) I am not to sure how one can use hyperators, well I meant the hyped hyperoperators, to juggle with lists and counting hashes. One may want to feed multiple arrays to a single hash or one array to multiple hashes. To add some salt to the problem "Multiple" can translate to an "array of" : my @ary_of_h of Hash; @ary_of_h += @a; Having real types in Perl6 will allow to slice, dice, splice data in many nice ways. Damian can even spice that with junctions. Fear. Fear. -- stef
Re: idiom for filling a counting hash
On Tue, 18 May 2004, Stéphane Payrard wrote: > I use over and over this idiom in perl5: > >$a{$_}++ for @a; > In perl6, using a hash slice and a hyper(increment)operator: [EMAIL PROTECTED];
Re: idiom for filling a counting hash
> "JW" == John Williams <[EMAIL PROTECTED]> writes: JW> On Tue, 18 May 2004, Stéphane Payrard wrote: >> I use over and over this idiom in perl5: >> >> $a{$_}++ for @a; JW> [EMAIL PROTECTED]; i see dead languages (apl :) uri -- Uri Guttman -- [EMAIL PROTECTED] http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs http://jobs.perl.org
Re: idiom for filling a counting hash
St?phane Payrard skribis 2004-05-18 23:14 (+0200): > I use over and over this idiom in perl5: >$a{$_}++ for @a; > This is nice and perlish but it gets easily pretty boring > when dealing with many list/arrays and counting hashes. A3 says something about tr being able to return a histogram (a hash like your %a), A5 says something about tr being able to match more than just characters. There must be some neat trick with tr that you can use for this :) But maybe it's better to just define a histogram method for arrays. Then you can get the unique elements by doing @array.histogram.keys. But again, just having a method for that is probably a better idea (if only because with the hash, the original order is lost). Juerd
Re: idiom for filling a counting hash
John Williams skribis 2004-05-18 16:07 (-0600): > >$a{$_}++ for @a; > [EMAIL PROTECTED]; That's not a bad idea, even in Perl 5: 1;0 [EMAIL PROTECTED]:~$ perl -MBenchmark=cmpthese -e'my @foo = (1..16, 1..10); cmpthese -1, { a => sub { my %foo; $foo{$_}++ for @foo; }, i b => sub { my %foo; $_++ for @[EMAIL PROTECTED]; } }' Rate a b a 51121/s -- -9% b 56220/s 10% -- Juerd
Re: idiom for filling a counting hash
StÃphane Payrard writes: > I use over and over this idiom in perl5: > >$a{$_}++ for @a; > > This is nice and perlish but it gets easily pretty boring > when dealing with many list/arrays and counting hashes. > > I thought overloading the += operator > >%a += @a; Though that would like to mean that: %a + @a Is %a with each of @a incremented. Which is quite nonsense, since it's the number of keys of %a plus the number of values of @a. Obviously adding to a hash means nothing, so there's no ambiguity with using +=, but it's that disagreement that makes me uneasy. But if you must, I believe it's possible: multi sub *infix:+= (%hash is rw, $scalar) is rw { ++%hash{$scalar}; %hash; } multi sub *infix:+= (%hash is rw, @array) is rw { ++Â [EMAIL PROTECTED]; %hash; } [snip] > Having real types in Perl6 will allow to slice, dice, splice data > in many nice ways. Damian can even spice that with junctions. > Fear. Fear. Yeah, junctions fit the purpose better, unless you're histogramming. Or better yet, since Junctions can only be in scalar variables, one might use | to mean hash union. my %a := { a => 1, b => 2 }; my %b := { b => 3, c => 4 }; %a | %b;#{ a => 1, b => 2, c => 4 } And what's better, adverbial modifiers will allow us to give a key union sub: %a | %b :union{ $^a + $^b } # { a => 1, b => 5, c => 4 } Or you could go APL and make another meta-operator: multi sub *infix_circumfix_meta_operator:â...â ($op) { sub (%a, %b) { %a | %b :union{ $op($^x, $^y) } } } So you get: %a â+â %b; # { a => 1, b => 5, c => 4 } And then: %a â+â= @a; Is the operator you want. But, after all that, ++Â [EMAIL PROTECTED] Was probably the best way to do it all along. Perl 6 frightens me. I love it. Luke
Re: idiom for filling a counting hash
On Tue, 2004-05-18 at 18:16, Juerd wrote: > St?phane Payrard skribis 2004-05-18 23:14 (+0200): > > I use over and over this idiom in perl5: > >$a{$_}++ for @a; > > This is nice and perlish but it gets easily pretty boring > > when dealing with many list/arrays and counting hashes. I never saw the original, but in Perl 5, you would probably just define a class which stored the information you needed. In Perl 6, it should be much easier to make that class behave the way you want syntactically, but for example in Perl 5 (wrap with tie to taste): package CountedArray; sub new { $obj=bless {}, $_[0]; $obj->push(@_) if @_; $obj } sub fetch { my $self = shift; my $index = shift; return $self->{array}[$index]; } sub store { my $self = shift; my $index = shift; my $data = shift; my $old = undef; if ($self->exists($index)) { $old = $self->fetch($index); $self->{counter}{$old}--; } $self->{array}[$index] = $data; $self->{counter}{$data}++; return $old; } sub exists { my $self = shift; my $index = shift; return exists @{$self->{array}}; } sub delete { my $self = shift; my $index = shift; if ($self->exists($index)) { $self->{counts}{$self->{array}[$index]}--; delete $self->{array}[$index]; } } sub count { my $self = shift; my $data = shift; return $self->{counter}{$data}; } sub counts { my $self = shift; return %{$self->{counter}}; } -- Aaron Sherman <[EMAIL PROTECTED]> Senior Systems Engineer and Toolsmith "It's the sound of a satellite saying, 'get me down!'" -Shriekback
RE: idiom for filling a counting hash
> -Original Message- > From: Luke Palmer > %a Â+Â= @a; > Is the operator you want. But, after all that, > > ++Â [EMAIL PROTECTED] > > Was probably the best way to do it all along. > Hmm. For junctions I was thinking: ++ all([EMAIL PROTECTED]); Which is almost readable. > Perl 6 frightens me. I love it. Umm, yeah. On any given day, I half-agree with you. =Austin
Re: idiom for filling a counting hash
Austin Hastings wrote: Hmm. For junctions I was thinking: ++ all([EMAIL PROTECTED]); Which is almost readable. But unfortunately not correct. Junctions are value, not lvalues. This situation is exactly what hyperoperators are for: ++Â [EMAIL PROTECTED]; Damian
RE: idiom for filling a counting hash
> -Original Message- > From: Damian Conway [mailto:[EMAIL PROTECTED] > Sent: Tuesday, 18 May, 2004 08:09 PM > To: [EMAIL PROTECTED] > Subject: Re: idiom for filling a counting hash > > > Austin Hastings wrote: > > > Hmm. For junctions I was thinking: > > > > ++ all([EMAIL PROTECTED]); > > > > Which is almost readable. > > But unfortunately not correct. Junctions are value, not lvalues. That'll have to be fixed. I suppose if you tried to mix l- and r-values it'd cause a new class of error (assuming the junction collapsed that way) but why not bundle lvalues together? =Austin
Re: idiom for filling a counting hash
Damian Conway writes: > Austin Hastings wrote: > > >Hmm. For junctions I was thinking: > > > > ++ all([EMAIL PROTECTED]); > > > >Which is almost readable. > > But unfortunately not correct. Junctions are value, not lvalues. > > This situation is exactly what hyperoperators are for: > > ++Â [EMAIL PROTECTED]; Er, did the hyper operator's direction flip? I thought it was: ++Â [EMAIL PROTECTED]; Luke
Re: idiom for filling a counting hash
On Tue, May 18, 2004 at 06:32:28PM -0600, Luke Palmer wrote: : Damian Conway writes: : > Austin Hastings wrote: : > : > >Hmm. For junctions I was thinking: : > > : > > ++ all([EMAIL PROTECTED]); : > > : > >Which is almost readable. : > : > But unfortunately not correct. Junctions are value, not lvalues. : > : > This situation is exactly what hyperoperators are for: : > : > ++» [EMAIL PROTECTED]; : : Er, did the hyper operator's direction flip? I thought it was: : : ++« [EMAIL PROTECTED]; There's a bug in the flight control softward that flips it 180° when you cross the equator. Larry
Re: idiom for filling a counting hash
On Tue, May 18, 2004 at 11:14:30PM +0200, Stéphane Payrard wrote: > I thought overloading the += operator > >%a += @a; There's been lots of discussion of this, but: > Probably that operator should be smart enough to be fed with > a mixed list of array and hashes as well: > > %a += ( @a, %h); # would mean %a += ( @a, keys %h) I would like this sort of "addition" of hashes to allow for two meanings. A counting hash can be used for testing whether a key exists, but also for how many times it has occurred. So (in Perl 5): add( %a, %b ) could work with: ++$a{$_} for keys %b only if you are only interested in existance, but it should work as: while( my($k,$v) = each %b ) { $a{$k} += $v; } so that you can merge one set of counts into another. In Perl 6, this could be a function (perhaps wrapped in an operator, I'm not especially concerned about that) that runs through its list of "keys" and increments the ones that are scalar, but for pairs it increments the key by the value. --
Re: idiom for filling a counting hash
Luke asked: Er, did the hyper operator's direction flip? I thought it was: ++Â [EMAIL PROTECTED]; My bad. 'Tis indeed. Damian
Re: idiom for filling a counting hash
Austin Hastings asked: Junctions are value, not lvalues. Why not bundle lvalues together? Because, although this would mean what it says: all($x, $y, $z)++; None of these would: any($x, $y, $z)++; one($x, $y, $z)++; none($x, $y, $z)++; We're trying to avoid introducing new features that encourage new mistakes. Damian
Re: idiom for filling a counting hash
> "J" == Juerd <[EMAIL PROTECTED]> writes: J> John Williams skribis 2004-05-18 16:07 (-0600): >> >$a{$_}++ for @a; >> [EMAIL PROTECTED]; J> That's not a bad idea, even in Perl 5: J> 1;0 [EMAIL PROTECTED]:~$ perl -MBenchmark=cmpthese -e'my @foo = (1..16, J> 1..10); cmpthese -1, { a => sub { my %foo; $foo{$_}++ for @foo; }, i J> b => sub { my %foo; $_++ for @[EMAIL PROTECTED]; } }' J> Rate a b J> a 51121/s -- -9% J> b 56220/s 10% -- but those are setting the empty hash to values of 1's. you can do that with a slice or map: @[EMAIL PROTECTED] = (1) x @foo ; my %foo = map { $_ => 1 } @foo ; add those to the benchmark. now if you wanted to increment the values of a hash already stuffed, then values is cool: $_++ for values %foo ; but i do like the hyper version in p6. i assume that this is ok since >> is not a logical shift anymore. [EMAIL PROTECTED]>>++; uri -- Uri Guttman -- [EMAIL PROTECTED] http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs http://jobs.perl.org
Re: idiom for filling a counting hash
Uri Guttman skribis 2004-05-19 0:08 (-0400): > J> 1;0 [EMAIL PROTECTED]:~$ perl -MBenchmark=cmpthese -e'my @foo = (1..16, > J> 1..10); cmpthese -1, { a => sub { my %foo; $foo{$_}++ for @foo; }, i > J> b => sub { my %foo; $_++ for @[EMAIL PROTECTED]; } }' > J> Rate a b > J> a 51121/s -- -9% > J> b 56220/s 10% -- > but those are setting the empty hash to values of 1's. you can do that > with a slice or map: Not in my perl. perl -MData::Dumper -le'my @foo = (1..16, 1..10); my %foo; $foo{$_}++ for @foo; print Dumper \%foo' perl -MData::Dumper -le'my @foo = (1..16, 1..10); my %foo; $_++ for @[EMAIL PROTECTED]; print Dumper \%foo' Both give: $VAR1 = { '11' => 1, '7' => 2, '2' => 2, '1' => 2, '16' => 1, '13' => 1, '6' => 2, '3' => 2, '9' => 2, '12' => 1, '14' => 1, '15' => 1, '8' => 2, '4' => 2, '10' => 2, '5' => 2 }; This is perl, v5.8.4 built for i386-linux-thread-multi Juerd