这是我的问题:对于我的一项任务,我的任务是开发一个lisp程序,它将2个列表作为输入,一个表示带有项目名称和数量的购物车(L1),第二个表示价格表(L2),带有商品名称和价格。一切都遵循这种格式:
(calcTotal '(shirtA 3 shirtB 1) '(shirtA 25 shirtB 55))
The total is 155.00
以下是我的代码:
(defun calcTotal (L1 L2 &aux(Ttl 0))
(cond
(
(and (listp L1) (listp L2))
(do
((tLst1 L1 (cddr tLst1)))
((equal tLst1 nil) Ttl)
(do
((tLst2 L2 (cddr tLst2)))
((equal tLst2 nil) nil)
(cond
(
(equal (car tLst1) (car tLst2))
(print (+ Ttl (* (cadr tLst1) (cadr tLst2))))
)
)
)
)
)
)
)
基本上,它所做的是检查第一个列表中项目的名称,然后在第二个列表中搜索它。找到匹配后,将它们的值相乘以得到该项的总和,然后删除第一个列表中的前两个元素,然后重复。问题是总(Ttl)不会累积。我可以专门得到每个项目的金额,但由于某种原因,Ttl返回为0.有谁可以告诉我为什么?
答案 0 :(得分:9)
至少有三种方法:
我会告诉你方法2:
一个重要的工具是功能抽象。使用函数实现自包含功能,可以重复使用,并且可以轻松测试。
你需要一个价格。写一个GET-PRICE
函数。
(defun get-price (item price-list)
(getf price-list item))
上面使用价格表作为属性列表。 GETF
进行查找。您可以将其重新实现为任务。
在列表中应用函数并收集返回值在列表中称为* mapping'。不幸的是,Lisp提供的映射函数只需要一个项目,而不是两个。我们写一个:
(defun map2 (function list)
(loop for (a b) on list by #'cddr
collect (funcall function a b)))
MAP2
映射到列表并在第一个和第二个参数上应用函数,然后是第三个和第四个参数,...它将结果收集到新列表中,然后返回该列表。
上面使用LOOP
构造。您可以使用DO
作为任务重新实现它。
(defun calc-total (cart price-list)
(reduce #'+
(map2 (lambda (item n)
(* n (get-price item price-list)))
cart)))
以上使用了两个高阶函数:REDUCE
和MAP2
。高阶意味着它们将函数作为参数。 REDUCE
是Common Lisp中的库函数。我们用它来总结一个数字列表。使用MAP2
,我们会计算每个购物车元素的价格,方法是将商品数量乘以每件商品的价格。
CL-USER > (calc-total '(shirtA 3 shirtB 1) '(shirtA 25 shirtB 55))
130
<强>概要强>
以上方法有几个优点:
对于其他方法,这里有提示:
答案 1 :(得分:8)
您的数据结构是Lisp属性列表:交替键和值对的平面列表(称为属性“指示符”和属性值)。
因此,您应该利用Lisp的属性列表操作函数,例如getf
,它会查找一个键并检索该值。
此外,loop
宏在这里有很大帮助。它擅长这样的总结工作。
(defun calculate-total (cart prices)
(loop for (item units) on cart by #'cddr
for unit-price = (getf prices item)
if unit-price
sum (* unit-price units)
else
do (error "price check on ~s please!" item)))
请注意我们如何很好地关闭像)))
这样的括号。当Lisp代码格式正确时,你训练你的大脑不要看到括号。不要浪费你的时间排队,不管怎样你都要训练自己。
答案 2 :(得分:4)
您只需打印出该值即可。为了以后保留它,还要设置变量:
;; (print (+ Ttl (* (cadr tLst1) (cadr tLst2))))
(setf Ttl (+ Ttl (* (cadr tLst1) (cadr tLst2))))
(print Ttl)