Stack Overflow的新成员。我试图找到Scheme中所有元素出现的索引但是我不确定如何推进我的代码超过以下内容 - 打印第一次出现 - 也许有人可以请求帮助:
(define positions
(lambda (A L)
(if (null? L)
-1
(if (eq? (car L) A)
0
(if (= (positions A (cdr L)) -1)
-1
(+ 1 (positions A (cdr L))))))))
答案 0 :(得分:2)
您需要一个帮助程序来保存额外的变量,例如您正在检查的当前索引:
(define (positions needle haystack)
(define (helper index haystack result)
(cond (<haystack empty> result)
(<first element matches needle>
<recurse increment index, cdr haystack and cons index to result>)
(else <recurse increment index, cdr haystack, same result>)))
(helper 0 haystack '()))
请注意,(define (a args ...) body ...)
与(define a (lambda (args ...) body ...))
相同。
答案 1 :(得分:1)
您的代码不使用任何类型的循环。为了得到所有事件,你必须以某种方式迭代。
在Scheme中,这通常通过使用named let
的递归来完成。在每次迭代期间,您都有一个索引变量i
,结果列表r
和剩余的输入列表L
,它们在每个迭代步骤中变小。
您的示例的if
子句可以简化。
如果在列表的第一个元素中找到值,则递增索引,将当前索引附加到结果列表并继续输入列表的其余部分。
如果没有匹配,则增加索引,但不要将索引添加到结果列表中,并继续使用剩余的输入列表。
当L
为空时,您已到达输入列表的末尾。在这种情况下,返回结果列表。您必须反转结果列表,因为cons
会在开头附加。
(define positions
(lambda (A L)
(let loop ((i 0)
(r '())
(L L))
(if (null? L)
(reverse r)
(if (eq? (car L) A)
(loop (+ i 1) (cons i r) (cdr L))
(loop (+ i 1) r (cdr L)))))))
通过将if子句放入循环的参数中,可以避免键入循环命令两次。
(define positions
(lambda (A L)
(let loop ((i 0)
(r '())
(L L))
(if (null? L)
(reverse r)
(loop (+ i 1)
(if (eq? (car L) A)
(cons i r)
r)
(cdr L))))))
BTW:Scheme不是静态类型为C或Java。这意味着您不需要在保留变量值中编码错误,因为它在C中用-1完成。在Scheme中,您返回false #f
或空列表'()
,或者您使用(error "Sorry")
抛出错误。
答案 2 :(得分:1)
@ceving添加回答,cond
也可以在循环中使用,可以使代码更清晰:
(define (positions A L)
(let loop ((i 0)
(r '())
(L L))
(cond
[(null? L)
(reverse r)]
[(eq? (car L) A)
(loop (+ i 1) (cons i r) (cdr L))]
[else
(loop (+ i 1) r (cdr L))]
)))
答案 3 :(得分:1)
第一个观察结果是,要返回所有解决方案,该函数应返回索引列表。如果找不到元素,则应该返回空列表。
第二个观察结果是,无论是否找到该元素,搜索都应该在列表的其余部分继续进行。
第三,我们需要一个额外的参数来跟踪当前的位置。
(define positions
(lambda (A L i)
(if (null? L)
'() ; not found
(if (equal? (car L) A)
(cons i ; found at index i
(positions A (cdr L) (+ i 1))) ; and continue
(positions A (cdr L) (+ i 1)))))) ; not found, continue
> (positions 'a '(a b a c a d) 0)
'(0 2 4)