[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] Random lines from a File



Brian McNett wrote:
> 
> This is a very quick & dirty script, which opens a file and prints five 
> lines from it at random.  The target file is a list of email addresses in 
> this instance, but it could be anything.
> 
> #!perl
> 
> my $myfile = q(some_file);
> my @data;
> my $length;
> my $i;
> 

If you're going to predeclare all your variables anyway, you might as well
'use strict;'  :-)


> open(IN, $myfile) and
>   (@data = <IN>) and
>   close(IN) or
>   die(qq($0: Failed on $myfile: $!\n)); # could use warn()
> 

If the file is empty, you will die with a bogus value in $!.  You should
have a separate die statement with an appropriate message for each
operation.


> $length = @data; # Magic! Assigns the length of the array to the scalar!
> 
> for ($i = 1; $i <= 5; $i++) {
>   print $data[rand($length - 1)];
>   }
> 

This will never select the last element in the array.

rand($length - 1) generates a random float greater than or equal to 0, and
_strictly less than_ $length - 1.  $length - 1 is the index of the last
element, but the highest integer you can get is $length - 2.

So, you should not be subtracting 1 there.



This might select the same line more than once.  Is that a bug or a
feature?


> I'm open for any suggestions as to improvements. Can it be made MORE 
> random?


Your script stores the entire file in memory at once.  I would prefer a
solution based on the one line-at-a-time method:

  #!perl -n
  $line = $_ unless int rand $.;
  END { print $line }
  __END__



Here is a solution for selecting multiple random lines.
The lines are returned in the same order they appeared in the input.
No line will be selected more than once.
If there are fewer than $count lines in the input, all the lines will be
printed.

Modify the BEGIN { } as desired.  On Unix I would make it
  BEGIN { $count = shift || 1 }


#!perl -n

BEGIN { $count = 5 }

if (int($count / rand $.)) {
    splice @lines, rand @lines, 1
        if @lines == $count;
    push @lines, $_;
}

END { print @lines }

__END__



Enjoy!

Ronald

===== Want to unsubscribe from this list?
===== Send mail with body "unsubscribe" to macperl-request@macperl.org