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

I know how to take a random line from a file but I need to use up all the questions in the file without using any of the questions more than once. I've looked around the site but couldn't find any examples. The only idea I have is turning the filehandle into an array. Anyway any help would be appreciated. Here's the code I have so far:
"print "This program will ask the user random questions from a file un +til all the questions have been answered."; if (open QUESTFILE, '<questions.txt') { $count=0; while ($q=<QUESTFILE>) { $question[$count]=$q; $count=$count+1; } } else { print "Could not read questions from file question.txt\n"; exit; } if (open ANSFILE, '>answers.txt') { $count=0; while ($a=<ANSFILE>) { $answer[$count]=uc($a); $count=$count+1; } } else { print "Could not read answers from file answers.txt\n"; exit; } srand; $times=0; while ($times<10) { $quest = int(rand ($#question+1)); print $question[$quest]; $ans = uc(<STDIN>); print ANSFILE $ans; $times=$times+1; } exit;"
I know the code is basic but I've only just started using perl so any advice would be good. cheers!

Replies are listed 'Best First'.
Re: Random lines from a file for a quiz
by sauoq (Abbot) on Aug 09, 2003 at 23:09 UTC
    Here's the code I have so far

    As your code seems to overwrite your "answers.txt" file, I suspect you haven't done much testing....

    In any case, reading the whole file into an array and then shuffling the array is one approach. Or, rather than shuffling, you could splice out a random line each iteration until there are no more lines left. If the file is so huge that you don't want to read the whole thing in (which is unlikely given the requirements) then, instead of reading the whole file into memory, you could scan it once and save offsets for each line in an array. Then you could shuffle your array of offsets and use seek() when it comes time to actually read the question in.

    That should be enough to get you started. As this appears to be a learning exercise, giving you code would probably be counterproductive.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: Random lines from a file for a quiz
by cfreak (Chaplain) on Aug 10, 2003 at 00:11 UTC

    Looks like you're on the right track, I would suggest using some more Perlish syntax ... for instance rather than print and exit when the open fails, use die and make sure to print the $! variable because it will contain why it died. Also you're using a while loop to put the file into an array but Perl can do that for you automagically. Finally alway use strict and possible warnings as they will help you to debug.

    I would probably tackle it like this:

    use strict; use warnings; "print "This program will ask the user random questions from a file un +til all the questions have been answered.\n"; open(QUESTFILE, 'questions.txt') or die "Couldn't open questions.txt: +$!\n"; my @questions = <QUESTFILE>; # slurps up the entire file close(QUESTFILE);

    Before I continue, your answer file confuses me... opening it with > overwrites it. And it looks like you are trying to read from it but then you don't do anything with its contents that I can see. I'm going to assume you just want to append the answers.

    # this opens the answers file for append open(ANSFILE,">>answers.txt") or die "Couldn't open answers for append +ing: $!\n"; # rather than a while loop and a variable just use a foreach # loop wi +th a range ... $_ will contain the number foreach(1 .. 10) { print $questions[ int( rand( scalar(@questions) ) )]; my $ans = uc(<STDIN>); print ANSFILE $ans; } close(ANSFILE); exit;

    The only thing about this code is that it has the potential to ask the same question twice. You might use a hash to keep track of which questions you've already asked but I'll leave that as a excersise for you :)

    Hope that helps!
    Chris

    Lobster Aliens Are attacking the world!
Re: Random lines from a file for a quiz
by benn (Vicar) on Aug 10, 2003 at 01:44 UTC
    Tie::File (which is like your filehandle->array idea) could come in handy here, especially if you've got *lots* of questions :)
    use Tie::File; use List::Util qw(shuffle); tie @questions, 'Tie::File',"questions.txt" or die $!; my @qnums = shuffle(0..$#questions); foreach (@qnums) { print $questions[$_]; # get answer & write to file etc. }
    Cheers, Ben.
Re: Random lines from a file for a quiz
by bobn (Chaplain) on Aug 10, 2003 at 06:26 UTC

    # UNTESTED @ar = <FILE>; while ( @ar) { my $ind = int rand scalar @ar; print "$ar[$ind)\n"; splice @ar, $ind, 1; }

    --Bob Niederman, http://bob-n.com
Re: Random lines from a file for a quiz
by TStanley (Canon) on Aug 10, 2003 at 10:57 UTC
    <BLOW INSTRUMENT="horn" TYPE="own">
        You might want to take a look at my module
    <BLOW>

    TStanley
    --------
      thanks for all the help I think I'm near enough on the right track. Thanks especially for telling me to use warnings and strict because i didn't know how useful they were so I didn't bother using them. Oh yeah the reason why i'm writing to the answer file is because i'm making a seperate program to mark the answers. It's an excercise my mate set but he won't tell me how to do it he said I'd learn more from this site. cheers again.
Re: Random lines from a file for a quiz
by waswas-fng (Curate) on Aug 11, 2003 at 00:01 UTC
    two little more things here, don't seed rand (as it is dont already on current versions of perl and redoing it makes it less random) and try not avoind $1 .. $9 and $a .. $b as normal variables they are used by sort and regex.

    -Waswas