Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Fun With Perl: Golf

by japhy (Canon)
on Dec 07, 2001 at 06:36 UTC ( #130140=perlmeditation: print w/replies, xml ) Need Help??

Here are the winning holes from the recent nigh-week-long golf competition on the "Fun With Perl" mailing list:
  1. Print the first 10 lines of a file.
    #!/usr/bin/perl -p 11..exit
  2. Print the last 10 lines of a file.
    #!/usr/bin/perl print+(<>)[-10..-1]
  3. Print a file in reverse.
    #!/usr/bin/perl -p $\=$_.$\}{
  4. Print the middle line (or two) of a file.
    #!/usr/bin/perl -p0 $_=$1while/.^(.+)^/sm
  5. Print the line count of a file, zero-padded, right-aligned.
    #!/usr/bin/perl printf"%010d\n",$.,<>
These are the shortest (or one of those shortest) for each of the five holes. A full list of entries can be found at my web site, and at

Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Replies are listed 'Best First'.
Re: Fun With Perl: Golf
by blakem (Monsignor) on Dec 07, 2001 at 13:21 UTC
    Thats some fine golfing... I might have to join the mailing list. ;-) The only one I could improve upon was number 5:
    #!/usr/bin/perl -n }{printf"%010d\n",$.
    Which is one char shorter if you don't count the command line opt...

    Update: The rules for this particular course counted the command line opts, so I'd take a three stroke penalty for ' -n' which puts me two strokes behind on the leader board...


Re: Fun With Perl: Golf
by dmmiller2k (Chaplain) on Dec 08, 2001 at 01:20 UTC

    Forgive my uninformedness, but why is it called 'golf'?


    I was asleep in class that day
      Forgive my uninformedness, but why is it called 'golf'?

      Google is your friend: Google

Re: Fun With Perl: Golf
by Boots111 (Hermit) on Dec 09, 2001 at 00:06 UTC

    I have seen a few golfs now and respect them quite a bit, but am often stuck looking them and thinking How the hell does that work. Perhaps some more experienced coders could explain exactly what some of these little tid bits do.

      As a blanket statement, please check the FWP archives as most of them are being or have been explained. I'll explain how my five entries worked.
      Here's, which prints the first 10 lines of a file.
      #!/usr/bin/perl -p 11..exit
      The code expands (loosely) to
      while (<>) { 11..exit; } continue { print }
      The 11..exit is the flip-flop operator, in void context (which is as good as scalar context). It returns true when the left-hand side is true, and continues doing so until the right-hand side is true. Since the left-hand side is a numeric constant, that value is compared to $. (as is documented). So once $. == 11 is true, Perl sees is exit is true, but that has a side-effect of exiting the program. Thus, the print statement is only reached for the first 10 lines.
      Here's, which prints the last 10 lines:
      #!/usr/bin/perl print+(<>)[-10..-1]
      Not very exotic. It reads all of the file into a list, and then takes the last 10 elements. There is a one-stroke trick here. print(1+2)*3 happens to parse as (print(1+2))*3, so you often need to do print((1+2)*3). But you can save a stroke with the unary + operator: print+(1+2)*3.

      Here's a more inventive solution of mine:

      #!/usr/bin/perl map--$.>9||print,<>
      This is written more normally as a for-loop:
      for (<>) { print unless --$. > 9; }
      This code reads all of the file into a list to be iterated over (and thus $. is the number of lines read). Then, for each iteration, we subtract one from $. and see if it's greater than 9. If it is, we don't print the line -- otherwise, we do. --$. will be 9 when we get to the 10th-to-last line.
      Here's -- it's not mine, since mine is the utterly simplistic print reverse <>. It's the shortest entry, and it's genius.
      #!/usr/bin/perl -p $\=$_.$\}{
      That code expands to:
      while (<>) { $\ = $_ . $\ } {; } continue { print }
      Do you notice how there is an empty block before the continue now? That moves the printing to the very end of the program (where it will only occur once). We place $_ at the BEGINNING of the $\ variable, so we end up getting the lines in reverse order. When we do print, $_ is empty, but we also print $\! Why? Because it's the output record separator... what a clever variable to use!
      Here's It's not the shortest, and it's pretty direct.
      #!/usr/bin/perl @_=<>;print@_[$#_/2..@_/2]
      If the number of lines is odd (13), we only print the ONE middle line. That means $#_/2 is going to be (13-1)/2 = 6, and @_/2 is going to be 13/2 = 6.5. The slice [6 .. 6.5] is as good as [6 .. 6]. However, if there are an even number of lines (20), we print the middle two. $#_/2 is then (20-1)/2 = 9.5, and @_/2 is 20/2 = 10; so our slice is [9.5 .. 10], which is just like [9 .. 10].
      Finally, here's, which I won with my first entry.
      #!/usr/bin/perl printf"%010d\n",$.,<>
      This prints the number of lines, zero-padded and right justified, to 10 digits. This makes use of the fact that by the time $. is accessed for its value, the <> has already returned all its lines, so $.'s value reflects that. So we print $. with the format, and "waste" the lines returned by <>.

      Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://130140]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (2)
As of 2018-05-21 00:19 GMT
Find Nodes?
    Voting Booth?