Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

global vars and one liners

by punkish (Priest)
on Sep 15, 2009 at 00:32 UTC ( [id://795252]=perlquestion: print w/replies, xml ) Need Help??

punkish has asked for the wisdom of the Perl Monks concerning the following question:

So, I am trying to learn one liners. I start with the following trivial script that loops over a DATA handle and prints out all the uniq words.

#!/usr/local/bin/perl while(<DATA>) { /(\w*)/; $i{$1}++; } print "$_\n" for keys %i; __DATA__ foo bar baz qux foo foo bar baz qux

Now, I want to convert this into a one liner, assuming the words are in a separate file called words.txt. So, I tried the following and failed

perl -nle '/(\w*)/;$i{$1}++;print for keys %i;' words.txt

The reason, of course, is that %i is not remembered from one iteration to the other. How do I create this one liner?

--

when small people start casting long shadows, it is time to go to bed

Replies are listed 'Best First'.
Re: global vars and one liners
by jethro (Monsignor) on Sep 15, 2009 at 01:16 UTC

    Wrong reason. i don't know what you got when you tried your one liner, but you should have seen something like this:

    foo foo bar foo bar baz ...

    (because of the randomness of the hash not exactly in this sequence)

    Reason is that your small for-loop is inside the while-loop created by -e.

    To rectify this you could replace the inner loop with an 'if':

    perl -nle '/(\w*)/; print if (not exists $i{$1}); $i{$1}++;' words.txt

    If you really need to do the printing after the loop, you could use END (the seldom used opposite of BEGIN):

    perl -nle '/(\w*)/;$i{$1}++; END{print for keys %i;} ' words.txt
Re: global vars and one liners
by AnomalousMonk (Archbishop) on Sep 15, 2009 at 01:09 UTC
    ... %i is not remembered from one iteration to the other.
    On the contrary,  %i is remembered perhaps too well, being printed entirely for every line (iteration) in the file. Consider the following modification (my file  words2.txt has the same data as given in the OP):
    >perl -nle "/(\w*)/; $i{$1}++; print qq{$. $_} for keys %i;" words2.txt 1 foo 2 bar 2 foo 3 bar 3 baz 3 foo 4 bar 4 baz 4 qux 4 foo 5 bar 5 baz 5 qux 5 foo 6 bar 6 baz 6 qux 6 foo 7 bar 7 baz 7 qux 7 foo 8 bar 8 baz 8 qux 8 foo 9 bar 9 baz 9 qux 9 foo
    Maybe try something like:
    >perl -wMstrict -lne "/(\w+)/; $::i{$1}++; END { print qq{$_ $::i{$_}} for keys %::i } " words2.txt bar 2 baz 2 qux 2 foo 3
    Update: removed extraneous  BEGIN { ... } block from second example.
      Or maybe just ditch the  -n command line switch altogether:
      >perl -wMstrict -le "for (<>) { /(\w+)/; $::i{$1}++ } print qq{$_ $::i{$_}} for keys %::i " words2.txt bar 2 baz 2 qux 2 foo 3
Re: global vars and one liners
by jwkrahn (Abbot) on Sep 15, 2009 at 08:34 UTC
    $ echo "foo bar baz qux foo foo bar baz qux" | perl -lne'@i{/\w+/g}=()}{print for keys%i' bar baz qux foo
      >perl -wMstrict -lne "@::i{ /\w+/g } = () }{ print for keys %::i" words2.txt bar baz qux foo
      OK, it works (Windose)! Now c'mon, how's it work? What's that strange  }{ thingy in the middle of it all? Can you give a documentation ref. for more info on that?

        It is so called eskimo operator: }{

        see perldoc perlrun about -n switch
        and compare output of the following two commands

        perl -MO=Deparse -ne "$a + $b" perl -MO=Deparse -ne "$a }{ $b"
        Note: double quotes because of Windows. Linux requires single quotes for the code given

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://795252]
Approved by ww
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2024-04-24 00:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found