我正在尝试编写一个函数来检查整数列表是否严格提升。我有以下内容:
(: ascending : (Listof Integer) -> Boolean)
;; test whether a list of integers is *strictly* ascending
(define (ascending x)
(match x
('() #f)
((cons hd tl)
(cond
((< hd (second x)) #t)
((> hd (second x)) #f)
(else (ascending tl))))))
它适用于前三个检查,但不适用于下面给出的最后三个检查:
(check-expect (ascending (list 1 2 3 4 5)) #t)
(check-expect (ascending (list 5 4 3 2 1)) #f)
(check-expect (ascending (list 5 1 2 3 4)) #f)
(check-expect (ascending (list 1 2 3 5 4)) #f)
(check-expect (ascending (list 1 3 2 4 5)) #f)
(check-expect (ascending (list 1 2 3 4 1)) #f)
我不明白我做错了什么,因为我必须做以下事情:
hd
和tl
以及hd
&lt; tl
然后#t
,如果不是#f
。完成勾选。 #t
或#f
。 请帮忙。
答案 0 :(得分:2)
你有一些问题。
首先,您错过了仅包含1个元素的列表的情况,该列表应该是基本情况,并返回#t
。否则,您将在仅包含1个元素的列表上使用(second x)
,这是一个错误。
接下来,当列表包含2个或更多元素时,如果第一个元素小于第二个元素并且列表的尾部也在升序,则它会升序。你只是检查前两个元素。您的else
子句仅在第一个和第二个元素相等时运行,因为前两个cond
检查处理<
和>
。递归调用不是一个单独的情况,它与前两个元素递增的情况相结合。
(define (ascending x)
(match x
('() #f) ;; Empty list is error
((cons hd '()) #t) ;; 1-element is success
((cons hd tl)
(if (< hd (second x))
(ascending tl)
#f))))
if
也可简化为:
(and (< hd (second x)) (ascending tl))
答案 1 :(得分:1)
由于函数#'<
接受任意数量的参数,您只需执行以下操作:
(apply #'< '(1 2 3 4)) => T
答案 2 :(得分:1)
如果您允许使用模式匹配来解决此问题,则可以使用更复杂的模式将问题分解为单独的部分。
(: ascending? : (Listof Integer) -> Boolean :)
(define (ascending? xs)
(match xs
[(list) #f] ;; empty list is not considered ascending
[(list a) #t] ;; single-element list is always ascending
;; match first two elements (a, b) and remaining elements as c
;; a should be less than b, and recurse
[(list a b c ...) (and (< a b) (ascending? (cons b c)))]))
对我而言,这比'()
或(cons ...)
样式匹配好很多。而且因为我们在第三种情况下使用了更具表现力的模式,它使实际执行的代码非常简单。
(ascending? '()) ;; => #f
(ascending? '(1)) ;; => #t
(ascending? '(1 2)) ;; => #t
(ascending? '(1 2 3 4 5 6 7)) ;; => #t
(ascending? '(1 2 3 1)) ;; => #f
我应该提到,你使用的其他风格模式没有任何问题。我认为当模式一致时,它更容易阅读。因此,如果您想使用带引号的模式,而不是将'()
与cons
和list
等匹配,请将它们用于每个案例,以便更容易看到您正在处理哪些案件。
这个ascending?
过程操作相同,只使用不同风格的模式匹配表达式
(: ascending? : (Listof Integer) -> Boolean :)
(define (ascending? xs)
(match xs
[`() #f]
[`(,a) #t]
[`(,a . (,b . ,c)) (and (< a b) (ascending? (cons b c)))]))
还有一件事:你说......
检查列表是否为空并引发错误。完成。剔
返回#f
不会引发错误。如果你真的打算在有人通过空列表时提出错误,那么你应该使用error
程序
...
(match xs
[(list) (error 'ascending? "empty list given")]
...
答案 3 :(得分:0)
对我而言,有时在问题描述中坚持使用更高级别的抽象是有帮助的,而不是将问题分解为适合编程模式,例如模式匹配。
例如,严格排序的列表可以说有两个数学属性:
列表已排序(单调)。
列表长度等于包含所有列表元素的集合的基数。
使用更多的数学规范:
#lang typed/racket
(: strictly-ordered-list? : (Listof Integer) -> Boolean)
(define (strictly-ordered-list? xs)
(define sorted (sort xs <))
(and (equal? xs sorted)
(= (set-count (list->set xs))
(length sorted))))
实现是在我们感兴趣的抽象层写的,列表。它测试列表的属性,并且在迭代和比较元素时不会陷入困境。它可能会以一定的速度进行交易,但通常对于有趣的大小数据,O(n log n)与O(n)不太可能成为瓶颈。
答案 4 :(得分:0)
也可以使用带有set!的迭代for循环,虽然这通常不是首选:
(define (asc? l)
(define res #t)
(for ((i (sub1 (length l)))
#:when (not(< (list-ref l i)
(list-ref l (add1 i)))))
(set! res #f)
)
res)
测试:
(asc? (list 1 2 3 4 5))
(asc? (list 1 2 3 4 5 4))
输出:
#t
#f