在Racket

时间:2016-08-08 14:20:19

标签: scheme racket

这似乎是一个大问题,但在以下3种计算真实项目数量的方法方面是否有任何显着差异?

#lang racket

(define (counttrue . vars)
  (length (remove* (list #f) vars))    )

(define (counttrue2 . vars)
  (define c 0)
  (for ((item vars))
    (when item (set! c (add1 c))))
  c    )

(define (counttrue3 . vars)
  (count (lambda(x) x) vars)    )

它们都会产生相同的结果,但有没有理由为什么应该或不应该选择特定的?

编辑:关于使用时间功能,以下3个函数获得以下结果,2个来自@ ChrisJester-Young和@Sylwester的答案:

"---------- counttrue ------------"
cpu time: 751 real time: 751 gc time: 16
"---------- counttrue2 ------------"
cpu time: 946 real time: 947 gc time: 10
"---------- counttrue3 ------------"
cpu time: 456 real time: 457 gc time: 8
"---------- counttrue_chris1 ------------"
cpu time: 726 real time: 727 gc time: 9
"---------- counttrue_chris2 ------------"
cpu time: 595 real time: 595 gc time: 8
"---------- counttrue_sylwester1 ------------"
cpu time: 543 real time: 544 gc time: 7
"---------- counttrue_sylwester2 ------------"
cpu time: 515 real time: 515 gc time: 7

因此,“计数lambda”方法是最快的。

2 个答案:

答案 0 :(得分:3)

count版本可能是最惯用的版本(除非我将其写为(count identity items))。此外,set!版本绝对不是惯用的Racket,而Racket并没有优化其使用,正如您可以从时序测试中看到的那样。

以下是您的计时乐趣的几种选择:

  1. 使用for理解:

    (for/sum ((x (in-list items)) #:when x) 1)
    
  2. 手动循环:

    (let loop ((sum 0)
               (items items))
      (cond ((null? items) sum)
            ((car items) (loop (add1 sum) (cdr items)))
            (else (loop sum (cdr items)))))
    

答案 1 :(得分:2)

他们只是做同样的不同方式。所有这些都是O(n)因此它们在时间上没有太大差别。他们中的一些人通过拥有一个中间名单而浪费了一点点记忆,但我认为你浪费了更多的时间进行比较,而不是通过选择最快的一个回来。我会根据你的第三个来选择那个最短​​且最重要的那个:

(define (count-true . args)
  (count values args))

它实际上只是一个专门的折叠:

(define (count-true . args)
  (foldl (lambda (val sum) 
           (if val (add1 sum) sum)) 
         0 
         args))

countfoldl都在let中使用名为#!racket的方式实施。