如何用符号替换嵌套列表中的数字?

时间:2011-09-10 00:47:16

标签: lisp common-lisp clisp

似乎我必须详细说明;这是我的功课。我不 想要复制你写的代码。我是新手;我在想什么 学习是如何将主题分解为单件,然后 专注于我应该用什么功能来解决问题。它是 我自己很难完成这些问题,因为我完全是这样 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语句来判断风速的类型:

    (如果(和(> x 39)(< x 73))(打印'热带)) (if(和(> x 74)(< x 95))(print'cat-1)) (if(和(> x 96)(< x 110))(打印'cat-2)) (if(和(> x 111)(< x 130))(print'cat-3)) (if(和(> x 131)(< x 155))(print'cat-4)) (if(和(> x 156))(print'cat-5))

  2. 用windtype替换windspeed(如65)(如cat-1

    storms 中的x循环       do(rplacd x'windtype)

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

3 个答案:

答案 0 :(得分:4)

DEFCONSTANT错了。使输入保持不变是没有意义的。用DEFVAR或DEFPARAMETER定义的变量很好。

而不是IF使用COND。 COND允许测试几种条件。

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

RPLACA也错了。那用于破坏性修改。你不希望这样。您想要创建一个新值。像RPLACA这样的东西可能会在函数DISTRIBUTION中使用(见下文)。

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

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

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

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

  • DISTRIBUTION,对于项目列表(标记类别),返回包含项目的列表(类别编号为此类别中的标记)。

  • STORM-DISTRIBUTION,对于项目列表(风暴类别)返回一个包含项目的列表(类别风暴数量在此类别中)。这基本上使用正确的参数调用DISTRIBUTION。

函数DISTRIBUTION是上面最复杂的。通常,人们会使用哈希表或关联列表作为中间帮助来保持事件的计数。映射输入列表并更新相应的计数。

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

答案 1 :(得分: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))

现在我们采用相同的风暴列表,但使用哈希表来跟踪每个类别中有多少风暴。 MAPCMAPCAR类似,但仅限于更新哈希表的副作用。 Ì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))

对我来说很好。

答案 2 :(得分: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