Rob Hudson wrote:

> > On 20010925.1701, Bob Miller said ...
> >
> > Rob Hudson wrote:
> > 
> > > I want to pick a random word from dict/words file, basically pick a
> > > random line in a file.
> > 
> > $ perl -ne '$l = $_ if ! int rand $n++; END { print $l }' /usr/dict/words
> 
> I found another version using perl and avoids the 'slurp the whole
> file into memory' approach...
> 
> cat /usr/share/dict/words | \ 
>   perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;'
> 
> 
> I can't see what yours is doing, though.  Care to explain?

They're basically the same.  I forgot about $. (aka $NR) so I used
a variable, $n, to count lines.  I used the "-n" flag to create the
loop implicitly.  According to the perlrun man page, perl -ne xxx
is equivalent to perl -e 'LINE: while (<>) { xxx }'.  So my code,
expanded, would be:

        LINE:
          while (<>) {
              $l = $_ if ! int rand $n++;
              END { print $l }
          }

$. (yours) is the current input line number, and $n (mine) is the
current line number minus one.  So mine has a bug -- the last line
in the file will never be selected.  I should have written ++$n
instead of $n++.

Of course, "! int rand <line-number>" is the same as
"rand(<line-number>) < 1".  The former truncates the random number
toward zero, and compares to zero, so it's true whenever the random
number is less than one.


And the overall command structure.  I wrote:

        $ perl args file

and you wrote:

        $ cat file | perl args

The call to srand is not needed.  See the "rand" section of
perlfunc(3).

So we can combine the best features of both versions and come up
with this.

$ perl -ne '$line = $_ if rand($.) < 1; END { print $line; }' /usr/dict/words

Of course, I'm avoiding the question of how this algorithm gives each
of the available words with equal probability, but trust me, it
does. (-:

-- 
Bob Miller                              K<bob>
kbobsoft software consulting
http://kbobsoft.com                     [EMAIL PROTECTED]

Reply via email to