【问题标题】:Keeping sublists in list form以列表形式保存子列表
【发布时间】:2017-02-27 03:22:54
【问题描述】:

我正在做一项作业,以遍历 DAG,寻找最短的路线。在一些 SO 答案的帮助下,我准备了很多东西。话虽如此,我无法获得一个返回子列表列表的函数,就像我需要进一步处理数据一样。数据文件有一个子列表列表,格式为(node1 node2 weight)

(define (children? node)
  (define list '(1))
  (map (lambda (x)
         (cond
           ((equal? (car x) node)
           (if (equal? list '(1))
               (set-car! list x)
           (append! list x)))))
   data)
(if (equal? list '(1))
  #f
  list))

(define (append! lst . lsts)
  (if (not (null? lsts))
  (if (null? (cdr lst))
      (begin
        (set-cdr! lst (car lsts))
        (apply append! (car lsts) (cdr lsts)))
      (apply append! (cdr lst) lsts))))

当我运行 (children?'b3) 时,我得到如下结果:

((b3 b5 57) b3 b4 81 b3 b10 55 b3 b14 61 b3 b13 66)

它实际上应该是什么样子

((b3 b5 57) (b3 b4 81) (b3 b10 55) (b3 b14 61) (b3 b13 66))

任何人都可以在这里阐明我的问题吗?

提前感谢您的帮助。

【问题讨论】:

  • 你的缩进全错了,如果没有必要,你不应该使用破坏性的列表修改,并且应该提供一个data实际样子的例子。话虽如此,您可能在应该使用listcons 的地方使用append

标签: scheme lisp sicp


【解决方案1】:

修复缩进,你的代码就变成了

(define (children? node)
  (define list '(1))

使用头部哨兵技巧。不错嘛...)。但由于它的目的是通过手术改变,它应该是新鲜制作的,而不是引用的数据:

  (define list (list 1))

等等,什么?两个lists?这不是 Common Lisp,是吗? Scheme 是 Lisp-1,而不是 Lisp-2;函数和值的名称位于同一个命名空间中;所以;不要。

  (define lst (list 1))

  (map (lambda (x)
         (cond
           ((equal? (car x) node)
              (if (equal? list '(1))
                  (set-car! list x)
                  (append! list x)))))

连续两个条件只是一个and,但更重要的是,头部哨兵技巧意味着您将返回真实结果为(cdr lst),因此无需更改其头部内容。然后代码进行了简化,这就是首先使用 head sentinel 的全部目的:

  (map (lambda (x)
         (if (equal? (car x) node)
             (append! lst x)))      ; changed the name

没有备用子句?一般来说,不赞成,但在这里你做地图是因为它的副作用,所以,只要你使用map的结果,你就可以了。更简单的方法是 always 根据习惯和良好风格处理备用子句,例如

  (map (lambda (x)
         (if (equal? (car x) node)
             (append! lst x)   ; append two lists together... (see below)
             #f))
       data)

data?那是什么?应该作为children?的另一个形参添加。

  (if (equal? lst '(1))

equal??为什么?要查看我们是否已对其进行了更改,只需

  (if (null (cdr lst))

最少动作原则...

      #f
      (cdr lst)))    ; cdr carries the true payload

(所以基本上,

(define (children? node data)
    (let ((res (filter (lambda (x) (equal? (car x) node)) 
                       data)))
      (if (not (null? res))
         res
         #f)))

)。好的。是吗?好吧,这取决于以下是否正常工作。

(define (append! lst . lsts)
  (if (not (null? lsts))
      (if (null? (cdr lst))
        (begin
          (set-cdr! lst (car lsts))
          (apply append! (car lsts) (cdr lsts)))

追加列表,所以(append! (list 1) (list 2)) 将返回与(list 1 2)(append! (list 1) (list 2 3)) 相同的结果(list 1 2 3)。要在列表末尾添加一个项目(如2),我们必须先将其放入另一个列表中。因此,如果我们要添加的项目本身就是一个列表,比如'(2 3),我们希望得到'(1 (2 3))。为此,必须在附加之前将项目包含在列表中。所以必须修改你的函数才能做到这一点。

      (apply append! (cdr lst) lsts))))

在这里,您扫描 (growth) 结果列表以查找其最后一个单元格,然后再次再次 查找要添加的每个项目。您可以通过自己维护最后一个单元格指针并直接使用它来解决这个问题。那个“指针”是什么?它是lst,每次你append! 时,你cdr 给它一些东西;所以你可以直接自己做(set-cdr! lst (list item))。您当然不能为此使用 lst 变量(为什么?)。

【讨论】:

    【解决方案2】:

    您的代码看起来您​​正在通过应用来自 Algol 编程经验(如 C 或 Java)的知识来学习 Scheme。在 Scheme 中,除非您有充分的理由这样做,否则您应该尝试在没有突变的情况下进行编程。保持大部分程序纯洁意味着更容易测试。

    命名约定很重要,并且以 ? 结尾的过程是一个谓词,因此它应该返回两个值之一,#t#f,就像在 Algol 语言中 isString 应该返回 true/false

    ;; graph constructor/accessors not not use car, cadr, etc
    ;; later you can change it to boxes
    (define (make-graph from to weight)
      (list from to weight))
    (define graph-from car)
    (define graph-to cadr)
    (define graph-wight cddr)
    
    ;; gets the graphs that has node as starting point
    (define (graphs-from node graphs)
      ; match? returns #t if graph starting point is the same as node
      ; since it's symbols we use eq?
      (define (match? graph)
        (eq? node (graph-from graph)))
    
      ; filters data by starting point
      ; this is the tail expression and thus the result of this procedure
      (filter match? graphs))
    
    (define data (list (make-graph 'x 'y 20)
                       (make-graph 'y 'x 30)
                       (make-graph 'w 'e 20)
                       (make-graph 'x 'e 13)))
    
    (graphs-from 'x data)
    ; ==> ((x y 20) (x e 13))
    
    (graphs-from 'a data)
    ; ==> ()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-23
      • 2014-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多