2011-04-20 33 views
7

是否可以这样做?假设我想获得列表的最后一个元素,我将创建一个变量i = 0,并将其增加,直到它等于长度。任何想法?一个例子将不胜感激。如何在Scheme函数内声明一个变量?

谢谢,

+1

你有什么算法来获取最后一个元素? – 2011-04-20 16:59:50

+0

@larsmans:遍历列表直到“i”等于长度?在计划中这听起来合理吗? – Chan 2011-04-20 23:04:08

+0

这听起来很浪费,因为你遍历列表两次;第一次计算长度。该算法将是线性时间(不像@ sepp2k所假设的那样是二次的),而是两次通过而不是惯用的。 – 2011-04-21 09:00:14

回答

11

有几种方法来声明一个变量;最干净的一个是let

(let ((x some-expr)) 
    ; code block that uses x 

但你并不需要它来获取列表的最后一个元素。只需使用递归:

(define (last xs) 
    (if (null? (cdr xs)) 
    (car xs) 
    (last (cdr xs)))) 

注意:如果你愿意,你可以使用一个变量来缓存cdr的结果:

(define (last xs) 
    (let ((tail (cdr xs))) 
    (if (null? tail) 
     (car xs) 
     (last tail)))) 
+0

非常感谢,非常好的解决方案!顺便说一句,我对上面的if语句有点困惑。 'last tail'属于'if'还是单独声明?我们如何区分? – Chan 2011-04-20 23:13:00

+1

@Chan:'(last tail)'是'if'表达式的其他部分。你可以通过parens和我使用缩进来判断。 – 2011-04-21 08:59:02

3

是的,它可以定义在方案中的局部变量,或者使用let或者define里面的一个函数。使用set!,也可以像您想象的那样重新分配一个变量。

这就是说,你可能不应该这样解决你的问题。在计划中,当你不需要时避免set!是一种很好的做法(在这种情况下,你肯定不需要)。进一步遍历使用索引的列表通常是一个坏主意,因为方案的列表是链接列表,因此随机访问O(n)(使last的功能与您想实现的功能相同)。

因此,一个没有索引的简单递归实现将比你打算做的更具惯用和更快,因此更可取。

+1

谢谢。我的问题是从列表中删除最后一个元素。我可以改变列表,然后删除第一个元素,但是效率太低了。与其他传统语言如C或C++相比,Scheme中的思考是完全奇怪的。 – Chan 2011-04-20 23:05:49

+0

除了使用'set!'之外,还有其他方法可以在Scheme中重新定义一个变量吗? – 2013-06-21 00:42:22