in reply to Re: Counting unique elements in an array
in thread Counting unique elements in an array

Here's a way that uses map in a non-void context:
use Data::Dumper; my %counts; my @array = qw (aa bb cc aa aa cc cc dd aa aa); %counts = map {$_ => ++$counts{$_} } @array; print Dumper(\%counts);
Here's another:
my %counts = map { my $n; do { $n = (($last=$_) ... ($last ne $_)) } while $n =~ /E0$/; ($last => $n); } sort @array;
Why they work is left as an exercise for the reader. ;-)

Caution: Contents may have been coded under pressure.

Replies are listed 'Best First'.
Re^3: Counting unique elements in an array
by Random_Walk (Prior) on Feb 08, 2005 at 18:01 UTC

    That is jumping through some hoops to avoid void. SuprisinglyUnsuprisingly (I just looked at it properly) the first one is a lot slower than the map in void context solution, the last one is slowest of all :)

    Updated

    added the for loop solution to the benchmark, it is nicely faster.
    #!/usr/bin/perl use strict; use warnings; use Benchmark; my @strings; my @array; push @strings, $_ x 2 for ("a" .. "z"); for (1..1000) { my $i=int rand $#strings; push @array, $strings[$i] } sub for_loop { my %sums; $sums{$_}++ foreach @array; # print "$_ = $sums{$_}\n" foreach sort keys %sums; } sub map_void { my %sums; map {$sums{$_}++} @array; # print "$_ = $sums{$_}\n" foreach sort keys %sums; } sub nonvoid_1 { my %sums; %sums = map {$_ => ++$sums{$_} } @array; # print "$_ = $sums{$_}\n" foreach sort keys %sums; } sub nonvoid_2 { my %sums; my $last=""; %sums = map { my $n; do { $n = (($last=$_) ... ($last ne $_)) } while $n =~ /E0$/; ($last => $n); } sort @array; # print "$_ = $sums{$_}\n" foreach sort keys %sums; } timethese( -3, {map_void => \&map_void, for_loop => \&for_loop, nonvoid_1 => \&nonvoid_1, nonvoid_2 => \&nonvoid_2 } ); __END__ Benchmark: running for_loop, map_void, nonvoid_1, nonvoid_2 for at lea +st 3 CPU seconds... for_loop: 3 wallclock secs ( 3.13 usr + 0.01 sys = 3.14 CPU) @ 15 +79.94/s (n=4961) map_void: 3 wallclock secs ( 3.19 usr + 0.00 sys = 3.19 CPU) @ 11 +65.83/s (n=3719) nonvoid_1: 3 wallclock secs ( 3.16 usr + 0.00 sys = 3.16 CPU) @ 33 +0.06/s (n=1043) nonvoid_2: 3 wallclock secs ( 3.28 usr + 0.00 sys = 3.28 CPU) @ 13 +9.33/s (n=457)

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
      That is jumping through some hoops to avoid void.
      Well, yeah. I was posting them in sort of a humor/brainteaser vein rather than as a serious solution to a problem that is (as has been pointed out)
      1. probably homework, and
      2. a FAQ

      Incidentally, here's a method that benches about 9% faster than for_loop:

      sub new_guy { my %sums; ++$_ for @sums{@array}; }

      Caution: Contents may have been coded under pressure.

        cunning indeed, significantly faster.

        Benchmark: running for_loop, map_void, new_guy, nonvoid_1, nonvoid_2 f +or at least 3 CPU seconds... for_loop: 4 wallclock secs ( 3.19 usr + 0.00 sys = 3.19 CPU) @ 15 +55.17/s (n=4961) map_void: 3 wallclock secs ( 3.29 usr + 0.00 sys = 3.29 CPU) @ 11 +30.40/s (n=3719) new_guy: 3 wallclock secs ( 3.07 usr + 0.00 sys = 3.07 CPU) @ 19 +67.10/s (n=6039) nonvoid_1: 3 wallclock secs ( 3.15 usr + 0.00 sys = 3.15 CPU) @ 33 +9.37/s (n=1069) nonvoid_2: 3 wallclock secs ( 3.15 usr + 0.01 sys = 3.16 CPU) @ 13 +9.87/s (n=442)

        Cheers,
        R.

        Pereant, qui ante nos nostra dixerunt!