views:

114

answers:

3

I'm learning Perl and building an application that gets a random line from a file using this code:

open(my $random_name, "<", "out.txt");
my @array = shuffle(<$random_name>);
chomp @array;
close($random_name) or die "Error when trying to close $random_name: $!";
print shift @array;

But now I want to delete this random name from the file. How I can do this?

+4  A: 
  1. shift already deletes a name from the array.

    So does pop (one from the beginning, one from the end) - I would suggest using pop as it may be more efficient and being a random one, you don't care which on you use.

  2. Or do you need to delete it from a file?

    If that's the case, you need to:

    A. get a count of names inside a file (if small, read it all in memory using File::Slurp, if large, either read it line-by-line and count or simply execute wc -l $filename command via backticks.

    B. Generate a random # from 1 to <$ of lines> (say, $random_line_number

    C. Read the file line by line. For every line read, WRITE it to another temp file (use File::Temp to generate temp files. Except do NOT write the line numbered $random_line_number to text file

    D. Close temp file and move it instead of your original file

  3. If the list contains filenames and you need to delete the file itself (the random file), use unlink() function. Don't forget to process return code from unlink() and, like with any IO operation, print error message containing $! which will be the text of system error on failure.

Done.

D.

DVK
Thanks very much DVK, very nice explained!
Nathan Campos
+2  A: 

When you say "delete this … from the list" do you mean delete it from the file? If you simply mean remove it from @array then you've already done that by using shift. If you want it removed from the file, and the order doesn't matter, simply write the remaining names in @array back into the file. If the file order does matter, you're going to have to do something slightly more complicated, such as reopen the file, read the items in in order, except for the one you don't want, and then write them all back out again. Either that, or take more notice of the order when you read the file.

Tim
+1  A: 

If you need to delete a line from a file (its not entirely clear from your question) one of the simplest and most efficient ways is to use Tie::File to manipulate a file as if it were an array. Otherwise perlfaq5 explains how to do it the long way.

Schwern
+1 - DVK's answer works (he explains the steps needed to manipulate a file), but your answer is better - less code to write and uses an abstraction layer.
Ether