Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: What does !$saw{$_}++ means

by Corion (Patriarch)
on Jan 26, 2005 at 08:39 UTC ( [id://425141]=note: print w/replies, xml ) Need Help??


in reply to What does !$saw{$_}++ means

Let's split it up a bit:

You have a hash, %saw. Individual elements of a hash are accessed via $hash{key}. If you append the postfix ++ operator to it, it looks like $saw{key}++, which increments the hash element by one.

Now, what does that do?

The grep iterates over the whole array @in, sets $_ to each element and then executes the code, in our case the expression !$saw{$_}++. If the expression returns a true value, grep keeps the array element in its result, otherwise it's discarded.

Now, when a key in %saw does not already exists, the code sets $saw{key} to 1 (incrementing by one from undef), and then returns the negation of the previous hash value (undef is false, so it returns true). So, if the hash key did not yet exist in the hash, the array element is put into @out.

The other case is that the hash key already exists in the hash. Then $saw{$_} returns a number greater than zero, which is interpreted as true, and the negation of that is false, so the (duplicate) array element in @in is discarded.

This method is a nice and easy way (once you understand it) to get a unique list of elements in an array while retaining the order. There are other methods, like using the keys of %saw:

undef %saw; $saw{$_}++ for @in; @out = keys %saw;

This code puts the same elements into @out, but you lose the order.

I don't remember if it was quicker, but there also is the non-looped version:

undef %saw; @saw{@in} = (1) x @in; @out = keys %saw;

Replies are listed 'Best First'.
Re^2: What does !$saw{$_}++ means
by ysth (Canon) on Jan 26, 2005 at 09:45 UTC
    returns the negation of the previous hash value (undef is false, so it returns true)
    Nit: post-increment returns 0 if the value was undef, not undef. This is occasionally criticised, defended, pointed out as inconsistent with post-decrement (which does return undef), and then dropped. A comment in pp.c refers one to http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2003-03/msg00536.html for further info (where you can read the criticism, defense, etc.).
Re^2: What does !$saw{$_}++ means
by Eimi Metamorphoumai (Deacon) on Jan 26, 2005 at 13:36 UTC
    I don't remember if it was quicker, but there also is the non-looped version:
    undef %saw; @saw{@in} = (1) x @in; @out = keys %saw;
    I haven't benchmarked it, but I've frequently heard it asserted that even faster is
    undef %saw; @saw{@in} = (); @out = keys %saw;
    That is, using undef as your values (so you don't need the increment or to create the list of ones).
Re^2: What does !$saw{$_}++ means
by ikegami (Patriarch) on Jan 26, 2005 at 17:06 UTC
    but there also is the non-looped version:

    Except that x is a loop operator, just like map. In fact, it not only loops for the number of duplications, it also implicitely loops over each element of the list on the LHS.

    @saw{@in} and keys(%saw) are also loops, but they are implicit unlike x.

    In fact, you can remove two of the four loops of your "non-looped version":

    undef %saw; undef(@saw{@in}); @out = keys(%saw);

    Update: undef %saw is also an implicit loop, on calls other than the first.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://425141]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (2)
As of 2024-04-20 04:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found