Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

A Random Fortune Cookie

by choroba (Cardinal)
on Mar 10, 2021 at 09:03 UTC ( [id://11129395]=CUFP: print w/replies, xml ) Need Help??

I follow the #perl hashtag on Mastodon. Few days ago, someone asked:

> Trying to randomize entries in a fortune text file. Not the output--the text of the human-readable fortune file. "sort -R" works on individual lines, but I want to grab multiline entries delimited by %.

To which someone else replied

> I figured it would be a two step solution. Step 1: install perl.

Another person reacted with

> <3 #perl. If you'd use a Perl one-liner let me know, I'll see if I can get one working. :)

The hashtag in this reply was why I was informed about the discussion.

Here's a sample from a typical fortune file (from ruanyf/fortunes):

You cannot achieve the impossible without attempting the absurd. % Assumption is the mother of all screw-ups. % Thinking you know something is a sure way to blind yourself. % Neckties strangle clear thinking. % The first principle is that you must not fool yourself -- and you are +the easiest person to fool. -- Richard Feynman % The greater danger for most of us lies not in setting our aim too high + and falling short; but in setting our aim too low, and achieving our + mark. -- Michelangelo % I would rather have a mind opened by wonder than one closed by belief. -- Gerry Spence % What you are is what you have been. What you'll be is what you do now. -- Buddha % What we see is mainly what we look for. %

And here's my solution:

perl -0x25 -MList::Util=shuffle -e 'print +(shuffle<>)[0]'

Update: As noted by hippo, the original request was more probably just to randomly sort the whole file. To do that, just remove the [0].

Update 2: Unfortunately, there's the trailing empty cookie problem.

perl -0x25 -MList::Util=shuffle -e '@f=<>;pop@f;print shuffle@f'

map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

Replies are listed 'Best First'.
Re: A Random Fortune Cookie
by Your Mother (Archbishop) on Mar 10, 2021 at 16:41 UTC

    This is a rather old, and clever, merlyn (IIRC) recipe.

    $/ = "\n\n"; rand($.) < 1 && ($line = $_) while <DATA>; print $line; __DATA__ You cannot achieve the impossible without attempting the absurd. Thinking you know something is a sure way to blind yourself. The first principle is that you must not fool yourself -- and you are +the easiest person to fool. -- Richard Feynman
      It's a special case of the Fisher-Yates shuffle, IIRC.

      map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
        AFAIK does Fisher-Yates start with the highest range in rand not the lowest.

        The proof may contain similar elements but I have trouble seeing the obvious analogy...

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

      Since $. is the number of the record, I'd guess this is a biased choice because only the first is guaranteed to be <1.

      Or do I miss a math trick to even the choices?

      update

      Actually it should work fine.

      You have to think it from the end, the n'th line has a 1/n chance which is correct.

      The line before is competing with the rest and has a 1/(n-1) chance, which is correct. °

      And so on, proof by induction.

      Indeed clever! =)

      update

      °) because the lines before have a combined chance of (n-1)/n and you have to multiply the odds. This leaves line n-1 with a chance of 1/n over all. .. :)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        You’re a *much* better mathematician than I. It’s from the Camel, 8.6. Picking a Random Line from a File. I can’t screenshot it or cut and paste it either because the text contains math images. The trick lies in reselecting lines as it goes and the odds of selection being “fair” across the entire file. As you say, one line is guaranteed to be picked. As subsequent lines are scanned, the odds of choosing them, and replacing the original selection, become proportionate to how many lines have been read.

        Update: didn’t see your update before I stubmitted. :P

Re: A Random Fortune Cookie
by Tux (Canon) on Mar 10, 2021 at 09:11 UTC
    perl -0x25 -e'chomp(@x=<>);print$x[int rand scalar @x]'

    Enjoy, Have FUN! H.Merijn
Re: A Random Fortune Cookie
by hippo (Bishop) on Mar 10, 2021 at 09:46 UTC

    I think this will sort the whole file which is what the OP may have really wanted.

    perl -MList::Util=shuffle -e '$/="\n%\n";print +(shuffle<>)' fortune.t +xt > randomised.txt

    🦛

Re: A Random Fortune Cookie
by bliako (Monsignor) on Mar 10, 2021 at 23:42 UTC

    And Now for Something Completely Different

    perl -0x25 -e '$_{$.}=$_ while<>; print join"\n",values%_;' # cookie number is a bonus: perl -0x25 -e '$_{$.}=$_ while<>; print join"\n"=>%_;'
    bw, --bliako

      some more variations:

      # no need to join perl -0x25 -e '$_{$.}=$_ while<>; print %_' # dumps one random cookie (not just shuffling): perl -0x25 -e '$_{$.}=$_ while<>; print ((%_)[$.==$.])' # and this but slicing it perl -0x25 -e '@_{<>}=1; print ((%_)[$.-$.]);' # not sure but this works too (re: looks like slice key is created aft +er slurping) perl -0x25 -e '@_{1..$.}=<>; print %_;'

      p.s. I did not know about -0x25, thanks

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://11129395]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2024-04-19 10:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found