[lug] perl :)

Tkil tkil at scrye.com
Thu Aug 15 23:43:30 MDT 2002


>>>>> "jd" == j davis <j> writes:

jd> @unique = grep { ++$count{$_} < 2 }
jd>                qw(a b a c d d e f g f h h);
jd> print "@unique\n";

jd> what does the qw do? 

perldoc perlop

it's "quote words".  think of qw(...) as "split ' ', q(...)", but done
at compile time.

what does q() do?  perldoc perlop.  :)  it's the single quote
function, which doesn't interpret anything other than \' and \\.

jd> and could i change 2 to say 3 if i wanted everything that apperad
jd> twice? Thanks....i am finally getting it I think!! :)

think about exactly what it's doing there.  'grep' evaluates its
expression for every element of the list given as its argument, and
passes on those elements where the expression evaluates to true.  so,
which values would give a true result there?  %count starts off empty;
the first time a value goes through, $count{$_} gets created and set
to undef; since there's a ++ in front of it, that value is
incremented, and the result of the increment is compared to see if
it's less than 2.  only the first occurance of each distinct element
will return true here, so you get a stable (order-preserving) set of
the elements in order of first appearance, with no duplicates.

remember, read stuff from the inside out.

you can't use this trick to find those that appear exactly twice or
thrice; it works for "first appearance" because you are dealing with
cardinal numbers, which can't go negative.

to find elements that appeared a certain number of times, i'd probably
do something like this:

  my @appears_twice = do { 
      my %count;  
      foreach my $elt (@list) { ++$count{$_} }
      grep { $count{$_} == 2 };
  }

if you want to do a histogram type thing, you could keep %count around
for longer.  as always, it depends on what you're trying to do.

you could also do a sort of inverted index:

  ... compute %count as above
  my %elts_with_count;
  while (my ($elt, $count) = each %count)
  {
      push @{ $elts_with_count{$count} }, $elt;
  }

  foreach my $count ( sort keys %elts_with_count )
  {
      print "$count: @{ $elts_with_count{$count} }\n";
  }

or similar.

t.



More information about the LUG mailing list