簡體   English   中英

球拍中的隊列?

[英]Queues in Racket?

我使用以下代碼來解決Sum by Factors

#lang racket
(provide sum-of-divided)

(define (sum-of-divided lst)
  (define (go ps n l)
    (define ((exhaust d) x)
      (define q (/ x d))
      (if (integer? q)
          ((exhaust d) q)
          (if (> x 1) `(,x) '())))
    (if (null? l)
        ps
        (if
          (for/or
            ([p ps])
            #:break (< n (sqr p))
            (= 0 (modulo n p)))
          (go ps (+ n 1) l)
          (go
            (append ps `(,n))
            (+ n 1)
            (append-map (exhaust n) l)))))
  (for*/list
    ([m (go '() 2 (map abs lst))]
     [s `(,(for/fold
       ([a '(0 #f)])
       ([x lst])
       (if (= 0 (modulo x m))
           `(,(+ (car a) x) #t)
           a)))]
     #:when (cadr s))
    `(,m ,(car s))))

令我驚訝的是,它通過了時間限制為 12 秒的測試,只有在我sequence-append L20 中的sequence-append更改為append sequence-append文檔說:

新序列是惰性構建的。

但是,事實證明,這顯然意味着除非需要,否則不會連接后續序列。 但是當需要它們的元素時,即序列sequence-append產生的sequence-append被消耗得足夠遠,時間成本與所有先前序列的長度之和成線性關系。 對? 這就是它慢的原因嗎?

如果是這樣,如何解決它? (在這種情況下, append性能足夠高,但假設我真的需要一個結構,它至少是一個具有通常復雜性的 FIFO 隊列。)在racket語言中是否有一個很好的替代方案,而不require額外的包(可能不可用,就像 Codewars 的情況一樣)? 差異列表可能(很容易從頭開始實現)?

我最終使用了明顯的,迄今為止故意避免的:可變列表:

#lang racket
(provide sum-of-divided)

(define (sum-of-divided lst)
  (define ps (mcons 0 '()))
  (define t ps)
  (for*/list
    ([m
      (let go ([n 2] [l (map abs lst)])
        (if (null? l)
            (mcdr ps)
            (go
              (+ n 1)
              (if
                (for/or
                  ([p (mcdr ps)])
                  #:break (< n (sqr p))
                  (= 0 (modulo n p)))
                l
                (begin
                  (set-mcdr! t (mcons n '()))
                  (set! t (mcdr t))
                  (remq*
                    '(1)
                    (map
                      (λ (x)
                         (let exhaust ([s x])
                           (define q (/ s n))
                           (if (integer? q)
                               (exhaust q)
                               s)))
                      l)))))))]
     [s `(,(for/fold
       ([a '(0 #f)])
       ([x lst])
       (if (= 0 (modulo x m))
           `(,(+ (car a) x) #t)
           a)))]
     #:when (cadr s))
    `(,m ,(car s))))

我還嘗試了一種使用流的純函數式方法:

#lang racket
(provide sum-of-divided)

(define primes
  (letrec
    ([ps
      (stream*
        2
        (for*/stream
          ([i (in-naturals 3)]
           #:unless
             (for/or
               ([p ps])
               #:break (< i (sqr p))
               (= 0 (modulo i p))))
        i))])
    ps))

(define (sum-of-divided lst)
  (for/fold
    ([l lst]
     [r '()]
     #:result (reverse r))
    ([d primes])
    #:break (null? l)
    (values
      (remq*
        '(1)
        (map
          (λ (x)
             (let exhaust ([s x])
               (define q (/ s d))
               (if (integer? q)
                   (exhaust q)
                   s)))
          l))
      `(,@(for/fold
          ([a 0]
           [f #f]
           #:result
             (if f
                 `((,d ,a))
                 '()))
          ([n lst])
           (if (= 0 (modulo n d))
               (values (+ a n) #t)
               (values a f)))
        ,@r))))

令人驚訝的是,它始終超時,而上面的命令式從未超時。 我相信 Racket 的實現者至少同樣關心功能風格的性能,我很失望。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM