简体   繁体   English

反转列表错误

[英]Reversing a list error

I'm learning DrRacket, and I need to write a program that reverses a list. 我正在学习DrRacket,并且需要编写一个可以反转列表的程序。 I have the below, and it's reversing the numbers, but somehow nesting them inside lists or something. 我有下面的内容,它正反转数字,但是以某种方式将它们嵌套在列表或其他内容中。

(define (reverse-list lon)
  (if (empty? lon)
      empty
      (cons (reverse-list (rest lon))
            (cons (first lon)
                  empty))))

Output of (reverse-list (list 1 2 3 4)): 输出(反向列表(列表1 2 3 4)):

(list (list (list (list empty 4) 3) 2) 1)

Anyone know why the output isn't just coming out as one list? 有人知道为什么输出不只是一个列表吗?

Thanks for the help! 谢谢您的帮助!

A cons has two cells. cons有两个单元格。 car and cdr . carcdr A cell can be displayed as (a . b) where a and b can be anything. 单元格可以显示为(a . b) ,其中ab可以是任何值。

There is an alternative representation to a pair. 一对有另一种表示形式。 If b is either another pair or the empty list you can just replace . b ) 如果b是另一对或空白列表,则可以替换. b ) . b ) with b without the initial ( . Thus: . b )b不带首字母(

(a . ())             ; ==> (a)
(a . (b . c))        ; ==> (a b . c)
(a . (b . (c . ()))) ; ==> (a b c)

Now for your code. 现在为您的代码。 Imagine you try it with (1 2 3 4) (or (1 . (2 . (3 . (4 . ())))) to be precise). 想象一下,您尝试使用(1 2 3 4) (或(1 . (2 . (3 . (4 . ()))))来进行尝试。 Using substitution rules we calculate exactly what your procedure does: 使用替换规则,我们可以精确地计算您的程序执行的操作:

(reverse-list '(1 . (2 . (3 . (4 . ())))))                   ; ==>
(if (empty? '(1 . (2 . (3 . (4 . ())))))
    empty 
    (cons (reverse-list (rest '(1 . (2 . (3 . (4 . ()))))))
          (cons (first '(1 . (2 . (3 . (4 . ()))))) 
                empty)))                                      ; ==>
(if #f
    empty 
    (cons (reverse-list (rest '(1 . (2 . (3 . (4 . ()))))))
          (cons (first '(1 . (2 . (3 . (4 . ()))))) 
                empty)))                                      ; ==>

(cons (reverse-list '(2 . (3 . (4 . ()))))
      (cons 1 empty))                                      ; ==>

(cons (cons (reverse-list '(3 . (4 . ())))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

(cons (cons (cons (reverse-list '(4 . ()))
                  (cons 3 empty))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

(cons (cons (cons (cons (reverse-list '())
                        (cons 4 empty))
                  (cons 3 empty))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

(cons (cons (cons (cons '()
                        (cons 4 empty))
                  (cons 3 empty))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

((((() . (4 . ())) . (3 . ())) . (2 . ())) . (1 . ()))     ; ==>
((((() . (4)) . (3)) . (2)) . (1))                         ; ==>
((((() 4) 3) 2) 1)

Now. 现在。 a True reversed list would have looked like this in dotted notation: 真实的反向列表将以点分符号显示如下:

(4 . (3 . (2 . (1 . ())))) ; ==> (4 3 2 1)

There is no way around it. 没有其他办法了。 You need to get quite intimate with cons and know you way around how the different ways to construct them gets displayed. 您需要与cons非常亲密,并了解如何显示构造它们的不同方法。 A hint would be that almost every list gets created from the end towards the beginning and iterated from the beginning to the end. 提示是几乎每个列表都是从头到尾创建的,并从头到尾进行迭代。

Nice to see you have solved your own problem. 很高兴看到您已经解决了自己的问题。 However I feel I should pick a little since reversing a list is realy building one on your way iterating. 但是我觉得我应该选择一点,因为反向列表确实可以按照您的方式建立一个迭代列表。

(define (reverse-list lon)
  ;; iterative helper procedure
  (define (aux lon acc)
    (if (empty? lon)
        acc
        (aux (rest lon) 
             (cons (first lon) acc))))
  ;; use helper
  (aux lon empty))

(reverse-list '(1 2 3 4)) ; ==> (4 3 2 1)

As you can see we iterate from beginning to end. 如您所见,我们从头到尾进行迭代。 As we do that we cons the current element to the accumulated list so far and that operation is from end to beginning. 这样做,到目前为止,我们将当前元素限制为累积列表,并且该操作是从头到尾的。 Ei the last added element will be the first in the result. Ei最后添加的元素将是结果中的第一个。 The nice thing about this is that we use one new cell for each cell processed and it's becomes part of the end result. 这样做的好处是,我们为每个处理的单元格使用一个新单元格,它已成为最终结果的一部分。 For each use of append you copy the first argument so a n element list gets (apply + (range n)) unnecessary cells allocated. 每次使用append您都将复制第一个参数,以便n元素列表获得(apply + (range n))不必要的单元分配。

A more seasoned Schemer would use a named let to do both the local procedure and call in one go: 经验更丰富的Schemer将使用命名的let来执行本地过程并一次调用:

(define (reverse-list lon)
  (let aux ((lon lon) (acc empty))
    (if (empty? lon)
        acc
        (aux (rest lon) 
             (cons (first lon) acc)))))

So, what ended up working was just replacing the first cons with an append to stop the list nesting. 因此,最终的工作是将第一个弊端替换为附加项以停止列表嵌套。

(define (reverse-list lon)
  (if (empty? lon) empty (append (reverse-list (rest lon)) (cons (first lon) empty))))

Problems solved, thanks for the help though. 问题已解决,不过感谢您的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM