【问题标题】:Scheme extract unique atoms from list方案从列表中提取唯一原子
【发布时间】:2013-06-27 11:58:33
【问题描述】:

我正在尝试编写一个方案函数,该函数将返回在输入列表中找到的唯一原子。

> (unique-atoms '(a (b) b ((c)) (a (b))))
(a c b)
> (unique-atoms '(a . a))
(a)
> (unique-atoms '())
()

我开始考虑这样的事情

(define (unique-atoms l)
  (if (null? l)
      '()
   (eq? (car (l) unique-atoms(cdr (l))))))

但我不知道如何收集唯一的原子,并在递归检查所有内容的同时创建一个新列表。

【问题讨论】:

  • (car (l))(cdr (l))(当 l 是一个列表时)是错误的。它们应该是 (car l)(cdr l)

标签: list scheme unique


【解决方案1】:

下面是list,一个学期一个学期。如果 next 值本身是一个列表,则使用 (append next rest) 进行递归调用 - 也就是说,在遍历 list 时,我们同时展平了子列表。

我们使用(尾)递归函数looking 来遍历列表并累积rslt。当next 不在rslt 中时,我们添加结果。

(define (uniquely list)
  (let looking ((rslt '()) (list list))
    (if (null? list)
        rslt
        (let ((next (car list))
              (rest (cdr list)))
          (if (list? next)
              (looking rslt (append next rest))
              (looking (if (memq next rslt)
                           rslt
                           (cons next rslt))
                       rest))))))
> (uniquely '(a b (a b) ((((a))))))
(b a)

如果您真的希望代码适用于像 '(a . a) 这样的“不适当的列表”,那么谓词 null?list? 可能需要更改。

【讨论】:

  • 更改谓词无济于事,因为还使用了append
  • 说检查谓词足以引发不正确的列表问题。有(append '(a b c) 'd) 生成了不正确的列表。
  • (append '(1 . 2) 3) 产生什么?
  • 而不是追加一个可以做(looking (looking rslt next) rest)。很多东西需要改变以支持dotted。 memq,新的基本案例等等。
【解决方案2】:

这个问题有两个部分:

  1. 您需要找到一种方法来访问给定表单的每个元素,递归到子列表中。
  2. 您需要一种方法来收集正在访问的独特元素。

这是第一部分的解决方案:

(define (recursive-fold visitor initial x)
  (let recur ((value initial)
              (x x))
    (cond ((null? x) value)
          ((pair? x) (recur (recur value (car x)) (cdr x)))
          (else (visitor x value)))))

我把它留给你来实现第二部分。

【讨论】:

  • 你能解释一下这个函数的参数以及它们的用途吗?
  • 当然,它采用与fold 相同的参数。事实上,它是一个左折叠,除了子列表也被遍历。如果您之前没有使用过fold,第一个参数(visitor)是一个带有两个参数的过程,我们称它们为elemlast-value。对于给定列表中的每个元素,您的过程被调用一次,elem 绑定到该元素,last-value 绑定到上一次调用过程返回的值(或 initial,如果这是第一次调用)。 x 是您正在遍历的列表。
  • 对不起,我仍然很难理解如何使用这个函数以及它有什么好处。我不知道该为测试参数提供什么以查看此函数在做什么。
  • 啊,所以你还没有了解fold,否则它的好处对你来说是显而易见的。 (它是函数式编程中最强大的操作之一,值得你花时间学习。)这很不幸,因为我很早就想在fold 上写一篇文章。事实上,这是我的 fold 文章的序言:dyscour.se/post/10113691502/5-ways-to-flatten-part-1
【解决方案3】:

我找到了一个半解决方案,其中非唯一项目被删除,尽管这不适用于原子 b 和带有 b 的列表,例如 '(b (b))

(define (uniqueAtoms l)
  (cond ((null? l)
         '())
        ((member (car l) (cdr l))
         (uniqueAtoms (cdr l)))
        (else
         (cons (car l) (uniqueAtoms (cdr l))))))

【讨论】:

  • 很好,听起来您已经实现了一半的解决方案。你只需要将它连接到我的recursive-fold,你就赢了!
【解决方案4】:

用各种列表结构解决这个问题最简单的方法就是把它分成两部分

1) 展平然后列出 - 这会产生一个没有子列表的正确列表

; if you use Racket, you can use the build-in flatten procedure
; otherwise this one should do
(define (flatten expr)
  (let loop ((expr expr) (res '()))
    (cond 
      ((empty? expr) res)
      ((pair? expr)  (append (flatten (car expr)) (flatten (cdr expr))))
      (else          (cons expr res)))))

2) 查找此正确列表的所有唯一成员

(define (unique-atoms lst)
  (let loop ((lst (flatten lst)) (res '()))
    (if (empty? lst)
        (reverse res)
        (let ((c (car lst)))
          (loop (cdr lst) (if (member c res) res (cons c res)))))))

测试:

; unit test - Racket specific
(module+ test
  (require rackunit)
  (check-equal? (unique-atoms '(a (b) b ((c)) (a (b)))) '(a b c))
  (check-equal? (unique-atoms '(a (b) b ((c . q)) (a (b . d)))) '(a b c q d))
  (check-equal? (unique-atoms '(a . a)) '(a))
  (check-equal? (unique-atoms '(a b (a b) ((((a)))))) '(a b))
  (check-equal? (unique-atoms '()) '()))

【讨论】:

  • 消除所有基于append 的扁平化实现是我的人生使命。抱歉,您的也已成为目标。更多解释:stackoverflow.com/a/13548087/13
  • 认真的吗?这不是一个与性能相关的问题,对于新手来说 append 比任何与 fold 相关的解决方案都更容易理解。
猜你喜欢
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 2019-08-01
  • 2018-12-08
  • 1970-01-01
相关资源
最近更新 更多