Scheme 是否统计方案中列表中元素的出现次数? 这是非常容易的,如果我可以在C++中使用命令行或map(树结构)中的数组。在计划中,我不知道如何开始这个想法?有人能帮我吗

Scheme 是否统计方案中列表中元素的出现次数? 这是非常容易的,如果我可以在C++中使用命令行或map(树结构)中的数组。在计划中,我不知道如何开始这个想法?有人能帮我吗,scheme,Scheme,谢谢,在球拍里,你可以做的 (count even? '(1 2 3 4)) 但更严重的是,使用Scheme中的列表执行此操作比您提到的要容易得多。列表要么是空的,要么是包含第一项和其余项的一对。在代码中遵循这个定义,你会让它“写出自己” 这里有一个开始的提示,基于(这是一本学习这些东西的好书)。从函数“header”开始——它应该接收一个谓词和一个列表: (define (count what list) ...) 为输入添加类型--what是一些值,list是一个内容列表: ;; c

谢谢,

在球拍里,你可以做的

(count even? '(1 2 3 4))
但更严重的是,使用Scheme中的列表执行此操作比您提到的要容易得多。列表要么是空的,要么是包含第一项和其余项的一对。在代码中遵循这个定义,你会让它“写出自己”

这里有一个开始的提示,基于(这是一本学习这些东西的好书)。从函数“header”开始——它应该接收一个谓词和一个列表:

(define (count what list)
  ...)
为输入添加类型--
what
是一些值,
list
是一个内容列表:

;; count : Any List -> Int
(define (count what list)
  ...)
现在,考虑到
列表的类型以及列表的定义(要么是空列表,要么是两件事的组合),我们需要检查它是哪种类型的列表:

;; count : Any List -> Int
(define (count what list)
  (cond [(null? list) ...]
        [else ...]))
第一种情况应该很明显:空列表中有多少<代码>哪些

对于第二种情况,您知道它是一个非空列表,因此您有两条信息:它的头部(使用
first
car
获取)和尾部(使用
rest
cdr
获取):


您现在需要做的就是找出如何组合这两条信息来获得代码。最后一点非常简单的信息是:由于(非空)列表的尾部本身就是一个列表,因此您可以使用
count
对其中的内容进行计数。因此,您可以进一步得出结论,您应该在其中使用
(count what(rest list))

在Scheme之类的函数式编程语言中,您必须以不同的方式思考并利用列表的构造方式。不是通过增加索引来迭代列表,而是递归地遍历列表。您可以使用
car
(单个元素)移除列表的头部,使用
cdr
(列表本身)获取尾部,还可以使用
cons
将头部和尾部粘在一起。您的功能概述如下:

  • 您必须将正在搜索的元素和当前计数“传递”到函数的每个调用
  • 如果你点击了空列表,你就完成了列表,你可以输出结果
  • 如果列表的car等于要查找的元素,则使用列表的cdr和计数器+1递归调用该函数
  • 如果不是,则使用列表的cdr和与前面相同的计数器值递归调用该函数

在Scheme中,您通常用作O(n)穷人的哈希表/字典。剩下的唯一问题是如何更新关联的元素。

您的问题不是很具体地说明要计算什么。我假设你想创建一些元素的频率表。有几种方法可以做到这一点。(如果您使用的是Racket,请向下滚动至底部以获得我的首选解决方案。)

便携式、纯功能性,但冗长且缓慢 这种方法使用关联列表(alist)来保存元素及其计数。对于传入列表中的每个项目,它在列表中查找该项目,并将其存在的值递增,如果不存在,则将其初始化为1

(define (bagify lst)
  (define (exclude alist key)
    (fold (lambda (ass result)
            (if (equal? (car ass) key)
                result
                (cons ass result)))
          '() alist))
  (fold (lambda (key bag)
          (cond ((assoc key bag)
                 => (lambda (old)
                      (let ((new (cons key (+ (cdr old) 1))))
                        (cons new (exclude bag key)))))
                (else (let ((new (cons key 1)))
                        (cons new bag)))))
        '() lst))
递增是有趣的部分。为了纯粹的功能性,我们实际上不能更改列表的任何元素,而是必须排除正在更改的关联,然后将该关联(使用新值)添加到结果中。例如,如果您有以下列表:

((foo . 1) (bar . 2) (baz . 2))
如果要在
baz
的值中添加1,则创建一个排除
baz
的新列表:

((foo . 1) (bar . 2))
然后将
baz
的新值添加回:

((baz . 3) (foo . 1) (bar . 2))
第二步是
exclude
函数所做的,可能是函数中最复杂的部分

便携、简洁、快速但不实用 更直接的方法是使用哈希表(来自SRFI 69),然后为列表中的每个元素逐段更新它。因为我们直接更新哈希表,所以它不是纯函数式的

(define (bagify lst)
  (let ((ht (make-hash-table)))
    (define (process key)
      (hash-table-update/default! ht key (lambda (x) (+ x 1)) 0))
    (for-each process lst)
    (hash-table->alist ht)))
纯功能、简洁、快速,但不便于携带 这种方法使用特定于Racket的哈希表(与SRFI 69的哈希表不同),它确实支持纯功能工作流。另一个好处是,这个版本也是三个版本中最简洁的

(define (bagify lst)
  (foldl (lambda (key ht)
           (hash-update ht key add1 0))
         #hash() lst))
您甚至可以使用
来理解以下内容:

(define (bagify lst)
  (for/fold ((ht #hash()))
            ((key (in-list lst)))
    (hash-update ht key add1 0)))

这更多地表明了可移植SRFI 69散列库的缺点,而不是执行纯功能任务的方案的任何特定失败。有了正确的库,这项任务可以在功能上轻松实现。

@Eli Barzilay:老实说,我不是在寻找完整的代码。此外,我看不出你的回答中有任何暗示。我理解cdr、汽车等。我要寻找的是如何构造每个元素出现的列表。例如,我遇到了
a
,将其增加了
1
,但是我应该存储
a
,以及如何存储?添加了详细的解释,而不是书籍参考:你真的应该读那本书@伊莱·巴兹莱:非常感谢。你能给我推荐一本书吗?我只是通过谷歌搜索来学习这门语言。(“not”应该是“note”。)如果你在自学这门语言,你绝对应该读它。它是免费的,而且是在线的,所以没有任何借口可以避免它。我在寻找一个想法,一个暗示,而不是一个完整的解决方案。另外,除了计划背后的理论,我在你的回答中没有看到任何暗示。@Chan:我给了你一个暗示。通过移除头部,检查它,然后递归地继续使用尾部来浏览列表。谢谢,这会更好。然而,我需要花一些时间来思考。我会让你知道的。我把汽车和cdr弄混了。我修好了。
(define (bagify lst)
  (for/fold ((ht #hash()))
            ((key (in-list lst)))
    (hash-update ht key add1 0)))