2

看来我得详细说一下了;这是我的作业。我不想复制你写的代码。我是新手;我正在尝试学习的是如何将主题分解为单个部分,然后专注于我应该使用什么功能来解决问题。我自己完成这些问题有点困难,因为我完全是 Lisp 的新手,实际上是如何编程。我希望你能帮助我。

问题是:有一个给定的常数

(defconstant *storms* '((bob 65)
                        (chary 150)
                        (jenny 145)
                        (ivan 165)
                        (james 120)))

每个风暴都由其名称和风速列表表示。

风速分类如下:

39–74 → tropical
75–95 → cat-1
96–110 → cat-2
111–130 → cat-3
131–155 → cat-4
156 或更多 →cat-5

现在我必须编写两个函数:

  • storm-categories应该生成类别名称,如下所示:(bob tropical), (chary cat-1), ...

  • 并且storm-distribution应该生成每个类别中的风暴数,如下所示:(cat-1 1), (cat-2 0), ...

我尝试解决这个问题的方法是:

  1. 使用if语句判断风速的类型:

    (if (and (> x 39) (< x 73)) (print 'tropical)) (if (and (> x 74) (< x 95)) (print 'cat-1)) (if (and (> x 96) (< x 110)) (print 'cat-2)) (if (and (> x 111) (< x 130)) (print'cat-3)) (if (and (> x 131) ( < x 155)) (print'cat-4)) (if (and (> x 156)) (print 'cat-5))

  2. 将风速 (like 65) 替换为 windtype (like cat-1)

    风暴中的 x 循环 做(rplacd x 'windtype)

我只是对第一个功能有一个简单的想法,但仍然不知道如何实现它。我还没有接触过分配功能,因为我仍然坚持第一个。

4

3 回答 3

4

DEFCONSTANT 是错误的。使您的输入成为常数是没有意义的。使用 DEFVAR 或 DEFPARAMETER 定义的变量很好。

代替 IF 使用 COND。COND 允许测试几个条件。

您不想使用 PRINT。为什么要打印一些东西。你想计算一个值。

RPLACA 也是错误的。这用于破坏性修改。你不想要那个。你想创造一个新的价值。函数 DISTRIBUTION 中可能会使用 RPLACA 之类的东西(见下文)。

使用功能抽象。哪些功能有用?

  • BETWEEN-P,是 a 和 b 之间的值 X 吗?

  • STORM-CATEGORY,对于给定的风速返回类别

  • STORM-CATEGORIES,对于项目列表(风暴风速)返回项目列表(风暴类别)。映射输入列表以创建结果列表。

  • DISTRIBUTION,对于项目列表(标签类别),返回一个包含项目的列表(类别数-标签-在-这个-类别中)。

  • STORM-DISTRIBUTION,对于项目列表(风暴类别),返回一个包含项目的列表(类别 number-of-storms-in-this-category)。这基本上使用正确的参数调用 DISTRIBUTION。

函数 DISTRIBUTION 是上述函数中最复杂的。通常,人们会使用哈希表或关联列表作为中间帮助来记录出现次数。映射输入列表并更新相应的计数。

另外: Common Lisp: A Gentle Introduction to Symbolic Computation 一书是对基本 Lisp 的一个很好的介绍——它可以以 PDF 格式免费下载。Lisp 的一个更有趣和基本的介绍是 Lisp Land of Lisp一书。

于 2011-09-10T00:55:37.700 回答
1

好的,roccia,你已经发布了你的答案。几分钟后我的黑客就来了,但它应该给你一些想法:

首先让我们从数据开始:

(defparameter *storms2004*
  '((BONNIE 65)
    (CHARLEY 150)
    (FRANCES 145)
    (IVAN 165)
    (JEANNE 120)))

(defparameter *storm-categories*
  '((39  73  tropical-storm)
    (74  95  hurricane-cat-1)
    (96  110 hurricane-cat-2)
    (111 130 hurricane-cat-3)
    (131 155 hurricane-cat-4)
    (156 nil hurricane-cat-5)))

检查值是否在两个边界之间的函数。如果右边界也可能丢失(NIL)。

(defun between (value a b)
  (<= a value (if b b value)))

请注意,Lisp 允许具有两个以上参数的比较谓词。

让我们找到风暴的类别。Lisp 函数FINDFIND-IF在列表中查找内容。

(defun storm-category (storm-speed)
  (third (find-if (lambda (storm)
                    (between storm-speed (first storm) (second storm)))
                  *storm-categories*)))

让我们计算每个风暴的类别。由于我们得到了(风暴风速)列表,我们只需映射计算列表中类别的函数。我们需要返回风暴和类别的列表。

(defun storm-categories (list)
  (mapcar (lambda (storm)
            (list (first storm)
                  (storm-category (second storm))))
          list))

现在我们采用相同的风暴列表,但使用哈希表来跟踪每个类别中有多少风暴。MAPC就像MAPCAR,但仅用于更新哈希表的副作用。ÌNCF 增加计数。当我们填满哈希表后,我们需要用MAPHASH. 对于表中的每一对键和值,我们只需将这对推送到结果列表中,然后返回该结果。

(defun storm-distribution (storms)
  (let ((table (make-hash-table)))
    (mapc (lambda (storm)
            (incf (gethash (second storm) table 0)))
          (storm-categories storms))
    (let ((result nil))
      (maphash (lambda (key value)
                 (push (list key value) result))
               table)
      result)))

测试:

CL-USER 33 > (storm-category 100)
HURRICANE-CAT-2

CL-USER 34 > (storm-categories *storms2004*)
((BONNIE TROPICAL-STORM)
 (CHARLEY HURRICANE-CAT-4)
 (FRANCES HURRICANE-CAT-4)
 (IVAN HURRICANE-CAT-5)
 (JEANNE HURRICANE-CAT-3))

CL-USER 35 > (storm-distribution *storms2004*)
((HURRICANE-CAT-5 1)
 (HURRICANE-CAT-4 2)
 (HURRICANE-CAT-3 1)
 (TROPICAL-STORM 1))

在我看来很好。

于 2011-09-14T08:21:50.363 回答
0

终于解决了这个问题。第二部分真的让我抓狂。我不知道如何使用哈希表或关联列表来解决它。无论如何,任务已经完成,但我想知道如何简化它......希望你们能帮助我。感谢您的帮助 Joswing,您的想法对我帮助很大...

(defconstant *storms2004* '((BONNIE 65)(CHARLEY 150)(FRANCES 145)(IVAN 165)(JEANNE 120)))

(defun storm-category (x) ; for given windspeed return the category
(cond
((and (> x 39) (< x 73) 'tropical-storm))
((and (> x 74) (< x 95) 'hurricane-cat-1))
((and (> x 96) (< x 110) 'hurricane-cat-2))
((and (> x 111) (< x 130) 'hurricane-cat-3))
((and (> x 131) (< x 155) 'hurricane-cat-4))
( t 'hurricane-cat-5)

)
);end storm-category

(defun storm-categories (lst) ;for a list of storm and windspeed return storm's name and wind type
(let ((result nil))
(dolist (x lst (reverse result)) ;
(push
(list (first x) (storm-category (second x)) ) result)
)

)

);end storm-categories

    (defun storm-distribution (lst)
    (setq stormcategories '(tropical-storm hurricane-cat-1 hurricane-cat-2 hurricane-cat-3 hurricane-cat-4 hurricane-cat-5))
    (setq stormlist (storm-categories lst))
     (let(    (tropicalcount 0)
              (hurricane-cat-1count 0)
              (hurricane-cat-2count 0)
              (hurricane-cat-3count 0)
              (hurricane-cat-4count 0)
              (hurricane-cat-5count 0)
              (result nil)
         )

    (dolist (y stormlist )

    (cond
         ((eql (second y) 'tropical-storm) (setq tropicalcount (+ tropicalcount 1)))
         ((eql (second y) 'hurricane-cat-1) (setq hurricane-cat-1count (+ hurricane-cat-1count 1)))
         ((eql (second y) 'hurricane-cat-2) (setq hurricane-cat-2count (+ hurricane-cat-2count 1)))
         ((eql (second y) 'hurricane-cat-3) (setq hurricane-cat-3count (+ hurricane-cat-3count 1)))
         ((eql (second y) 'hurricane-cat-4) (setq hurricane-cat-4count (+ hurricane-cat-4count 1)))
         ((eql (second y) 'hurricane-cat-5)(setq hurricane-cat-5count (+ hurricane-cat-5count 1)))
    )
    );ebd dolist


    (push
          (list  (list 'tropicalstorm tropicalcount ) 
                 (list 'hurricane-cat-1 hurricane-cat-1count) 
                 (list 'hurricane-cat-2  hurricane-cat-2count ) 
                 (list 'hurricane-cat-3  hurricane-cat-3count ) 
                 (list 'hurricane-cat-4  hurricane-cat-4count ) 
                 (list 'hurricane-cat-5  hurricane-cat-5count ) 
          ) ;end list
    result) ;end push

    );end let

    );end distribution
于 2011-09-14T07:27:44.917 回答