#!/bin/sh #| -*- scheme -*- exec mzscheme "$0" "$@" |# #lang scheme/base (require scheme/cmdline scheme/port) (define read-lines (case-lambda [() (for/list ([line (in-lines)]) line)] [(n) (for/list ([line (in-lines)] [i (in-range n)]) line)])) (define-struct ring (vec [len #:mutable])) (define (list->ring l) (let ([v (list->vector l)]) (make-ring v (vector-length v)))) (define (ring-empty? r) (zero? (ring-len r))) (define (ring-randpop! r) (let ([len (ring-len r)]) (if (zero? len) (error 'ring-randpop! "random ring is empty") (let* ([i (random len)] [v (ring-vec r)] [x (vector-ref v i)]) (vector-set! v i (vector-ref v (sub1 len))) (set-ring-len! r (sub1 len)) x)))) (define (ring-randset! r x) (vector-set! (ring-vec r) (random (ring-len r)) x)) (define (ring-randdisplay r) (let loop () (unless (ring-empty? r) (display (ring-randpop! r)) (newline) (loop)))) (define (output-n-random-lines n) (define r (list->ring (read-lines n))) (let loop ([m n]) (let ([line (read-line)]) (if (eof-object? line) (ring-randdisplay r) (let ([m (add1 m)]) (when (< (random m) n) (ring-randset! r line)) (loop m)))))) (define (output-randomized-lines) (ring-randdisplay (list->ring (read-lines)))) (define (run) (if num (output-n-random-lines num) (output-randomized-lines))) (define num #f) (command-line #:once-any [("-n") n "show n random line" (set! num (or (string->number n) (error 'random-lines "bad number: ~s" n)))] #:args files (cond [(null? files) (run)] [(null? (cdr files)) (with-input-from-file (car files) run)] [else (let-values ([(in out) (make-pipe 4096)]) (thread (lambda () (for ([file files]) (with-input-from-file file (lambda () (copy-port (current-input-port) out)))) (close-output-port out))) (parameterize ([current-input-port in]) (run)))]))