如何用 Racket 语言为嵌套列表创建计数器?

How can I create a counter for a nested list in the Racket language?

我正在尝试在 Dr Racket 中创建一个计数器,它将遍历嵌套列表并输出计数。

I currently have this code(我把所有的3都留在了列表中)

当前正在输出3(这是前三个3) 我假设它到达第一个嵌套列表的末尾并在该点停止,但我似乎无法弄清楚该怎么做。 (是的,这是一个作业,但这是我们在 racket 中的第二个作业,也是 spring 休息时间。我们回去的那天就到期了)

    (define (genCounter lst target c)
      (cond
         ((empty? lst) c)
         ((list? (first lst))
          (genCounter (first lst) target c))
         ((eq? (first lst) target)
          (genCounter (rest lst) target (+ c 1)))
         (else
          (genCounter (rest lst) target c))))

我不指望你给我答案,只是解释一下应该改变什么,或者比我的教授教我更多关于这门语言的知识。

所以我更改了用于 (genCounter '(3 (3 3 (3 3 3)) 3 (3 (3))) 3 0) 的列表,它返回了 6(我测试发现它是前 6 个被返回。我相信当它到达其中一个列表的末尾时,它会停止通过该函数,但就像我说的,我不知道要修复它到底要实现什么(虽然我知道它有什么问题)。

这是我最终创建的:

     (define (genCounter lst target)
      (if (null? lst) 0
          (let ((current (first lst)))
            (cond
              ((list? current)
               (+ (genCounter current target) (genCounter (rest lst) target)))
              ((eq? current target)
               (+ 1 (genCounter (rest lst) target)))
              (else
               (genCounter (rest lst) target))))))

首先,我们不要将标识符命名为listlist是构造列表的函数。如果您使用此名称,您将隐藏它,因此将无法在函数中使用它!下面,我将使用 lst 代替。

现在,对于你的问题,答案是,你的第二个分支是错误的:

[(list? (first lst)) (genCounter (first lst) val c)]

这样做的是:"if the first element is a list, dive into this sublist, count things, and then answer".

你能看出为什么不对吗?

假设您要计算以下列表中的 2:

(list (list 2 2 2) 2 (list 2 (list 2)))

因为第一个元素(list 2 2 2)是一个列表,它深入到这个子列表中并计数2。答案是3。但是,预期输出是6!

问题是,你不想只在第一个元素中计算 2,你想在

中计算 2
(list ... >>> 2 (list 2 (list 2)) <<<)

还有。

也就是说,你想在第一个元素中计数2之后,在列表的其余部分中计数2,然后将它们相加。

既然你现在有了一个可行的解决方案,我会告诉你

替代您的工作代码

(define (genCounter lst target)
  (if (empty? lst)
      0
      (+ (genCounter (rest lst) target) 
         (let ((x (first lst)))
           (if (list? x)
               (genCounter x target) 
               (if (eqv? x target) 1 0))))))

注意

  • 代码中的冗余较少,代价是在第一个元素不匹配时添加 0
  • 您不应使用 eq? 作为数字,而应使用 =eqv?;看看 equal?

与累加器一起工作的代码(就像在您的第一个版本中一样)

(define (genCounter lst target)
  (let loop ((lst lst) (count 0))
    (if (empty? lst)
        count
        (loop (rest lst)
              (let ((x (first lst)))
                (if (list? x)
                    (loop x count)
                    (if (eqv? x target) (add1 count) count)))))))

感兴趣:

  • 我将累加器 count 移动到一个内部过程(在本例中是一个命名的 let),它不应该是主过程签名的一部分
  • 所有魔法都发生在最后对 loop 的递归调用中,如果第一个元素是列表,则包括 附加 递归调用。