我想编写一个 Racket 函数,它接受一个列表并返回该列表中最小元素的位置。我已经编写了一个有效的函数:
(define (min-position xs)
(define (min-position2 count pos xs)
(cond ((null? xs) #f)
((= 1 (length xs)) pos)
((< (car xs) (cadr xs))
(min-position2 (+ count 1) pos (cons (car xs) (cddr xs))))
(else (min-position2 0 (+ count pos 1) (cons (cadr xs) (cddr xs))))))
(min-position2 0 0 xs))
示例输入和输出:
> (min-position '(9 8 7 6 5))
4
> (min-position '(9 8 1 6 5))
2
> (min-position '(0 1 2))
0
但是有没有更优雅的写法呢?
最佳答案
我不确定您所说的“优雅”是什么意思。例如,可能有一个 spiffier 算法。但这是我如何在保留您的基本方法的同时使代码更具可读性(恕我直言)。
一步一步:
您的输入/输出示例,重写为 check-equal?
测试:
#lang racket
(require rackunit)
(define (test f)
(check-equal? (f '(9 8 7 6 5)) 4)
(check-equal? (f '(9 8 1 6 5)) 2)
(check-equal? (f '(0 1)) 0)
(check-equal? (f '(0 1 2)) 0))
您的原始版本,但在 cond
子句中使用 [] 而不是 ()。
(define (min-position/v0 xs)
(define (min-position2 count pos xs)
(cond [(null? xs) #f]
[(= 1 (length xs)) pos]
[(< (car xs) (cadr xs))
(min-position2 (+ count 1) pos (cons (car xs) (cddr xs)))]
[else
(min-position2 0 (+ count pos 1) (cons (cadr xs) (cddr xs)))]))
(min-position2 0 0 xs))
(test min-position/v0)
使用 match
解构列表并使用 this
和 next
之类的名称代替 (car xs)
和 (cadr xs)
:
(define (min-position/match xs)
(define (min-position2 count pos xs)
(match xs
[(list) #f]
[(list _) pos]
[(list this next more ...)
(cond [(< this next)
(min-position2 (+ count 1) pos (cons this more))]
[else
(min-position2 0 (+ count pos 1) (cons next more))])]))
(min-position2 0 0 xs))
(test min-position/match)
将内部函数更改为 let loop ...
。完全一样,只是更简洁了一点。
(define (min-position/match&loop xs)
(let loop ([count 0] [pos 0] [xs xs])
(match xs
[(list) #f]
[(list _) pos]
[(list this next more ...)
(cond [(< this next) (loop (+ count 1) pos (cons this more))]
[else (loop 0 (+ count pos 1) (cons next more))])])))
(test min-position/match&loop)
同样,这与您的原始算法相同。但我会发现快速理解更容易。
关于list - 列表中最小元素的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23133351/