Stream merge: Difference between revisions

Content added Content deleted
m (→‎{{Header|Perl 6}}: Minor formatting edits to make automated testing easier)
Line 1,047: Line 1,047:
for item in heapq.merge(open(source) for source in sources):
for item in heapq.merge(open(source) for source in sources):
print(item)</lang>
print(item)</lang>

=={{header|Racket}}==

<lang racket>;; This module produces a sequence that merges streams in order (by <)
#lang racket/base
(require racket/stream)

(define-values (tl-first tl-rest tl-empty?)
(values stream-first stream-rest stream-empty?))

(define-struct merged-stream (< ss v ss′)
#:mutable ; sadly, so we don't have to redo potentially expensive <
#:methods gen:stream
[(define (stream-empty? S)
;; andmap defined to be true when ss is null
(andmap tl-empty? (merged-stream-ss S)))

(define (cache-next-head S)
(unless (box? (merged-stream-v S))
(define < (merged-stream-< S))
(define ss (merged-stream-ss S))
(define-values (best-f best-i)
(for/fold ((F #f) (I 0)) ((s (in-list ss)) (i (in-naturals)))
(if (tl-empty? s) (values F I)
(let ((f (tl-first s)))
(if (or (not F) (< f (unbox F))) (values (box f) i) (values F I))))))
(set-merged-stream-v! S best-f)
(define ss′ (for/list ((s ss) (i (in-naturals)) #:unless (tl-empty? s))
(if (= i best-i) (tl-rest s) s)))
(set-merged-stream-ss′! S ss′))
S)

(define (stream-first S)
(cache-next-head S)
(unbox (merged-stream-v S)))

(define (stream-rest S)
(cache-next-head S)
(struct-copy merged-stream S [ss (merged-stream-ss′ S)] [v #f]))])

(define ((merge-sequences <) . sqs)
(let ((strms (map sequence->stream sqs)))
(merged-stream < strms #f #f)))

;; ---------------------------------------------------------------------------------------------------
(module+ main
(require racket/string)
;; there are file streams and all sorts of other streams -- we can even read lines from strings
(for ((l ((merge-sequences string<?)
(in-lines (open-input-string "aardvark
dog
fox"))
(in-list (string-split "cat donkey elephant"))
(in-port read (open-input-string #<<<
"boy"
"emu"
"monkey"
<
)))))
(displayln l)))

;; ---------------------------------------------------------------------------------------------------
(module+ test
(require rackunit)
(define merge-sequences/< (merge-sequences <))
(check-equal?
(for/list ((i (in-stream (merge-sequences/< (in-list '(1 3 5)))))) i)
'(1 3 5))
;; in-stream (and in-list) is optional (but may increase performance)
(check-equal? (for/list ((i (merge-sequences/<))) i) null)
(check-equal? (for/list ((i (merge-sequences/< '(1 3 5) '(2 4 6)))) i) '(1 2 3 4 5 6))
(check-equal? (for/list ((i (merge-sequences/< '(1 3 5) '(2 4 6 7 8 9 10)))) i)
'(1 2 3 4 5 6 7 8 9 10))
(check-equal? (for/list ((i (merge-sequences/< '(2 4 6 7 8 9 10) '(1 3 5)))) i)
'(1 2 3 4 5 6 7 8 9 10)))</lang>

{{out}}

<pre>aardvark
boy
cat
dog
donkey
elephant
emu
fox
monkey</pre>


== {{header|REXX}} ==
== {{header|REXX}} ==