在lisp中组合两个列表以输出某个项目

时间:2015-04-10 14:00:57

标签: list lisp common-lisp

我目前已经解决了帆布背包问题,并且有两个列表,如下面的

清单1((帽子10 5)(衣服10 10)(帐篷40 70))

清单2(((1 1 1).0)((1 0 1).23)((1 0 0).45)((0 0 0).0))

清单2表示是否采取了项目。((1 1 1).0)表示所有采取的项目,0代表它是多么有用。我的最终输出是二进制,但我想知道如何创建一个带有两个列表并显示实际项目的函数,如下面的示例

取代打印((1 0 1).23) 打印((帐篷).23))

1 个答案:

答案 0 :(得分:1)

如果我理解正确,听起来你有一个基本上是面具的列表,以及相同长度的项目列表,并且对于面具的每个元素,你想从相应的项目中收集一些东西在项目列表中。我不确定这个函数的最佳名称是什么,但是这里的实现称之为 decode

(defun decode (mask items &key (key 'identity) (test 'identity))
  (loop
     for bit in mask
     for item in items
     when (funcall test bit)
     collect (funcall key item)))

CL-USER> (decode '(nil t nil nil t) '(a b c d e))
; (B E)
CL-USER> (decode '(nil t nil nil t) '(a b c d e) :key 'symbol-name)
; ("B" "E")
CL-USER> (decode '(nil t nil nil t) '(a b c d e) :test 'null)
; (A C D)

将这一点应用于您的用例并不难;测试是掩码元素是否为非零,键功能是优先,因为你想要项目的名称:

(defparameter *items*
  '((hat 10 5) (clothes 10 10) (tent 40 70)))

(defparameter *solutions*
  '(((1 1 1) . 0) ((1 0 1) . 23) ((1 0 0) . 45) ((0 0 0) . 0)))

(decode '(1 0 1) *items*
        :key 'first
        :test (complement #'zerop))
;;=> (hat tent)

(mapcar #'(lambda (solution)
            (cons (decode (car solution)
                          *items*
                          :key 'first
                          :test (complement #'zerop))
                  (cdr solution)))
        *solutions*)
;;=> (((HAT CLOTHES TENT) . 0) ((HAT TENT) . 23) ((HAT) . 45) (NIL . 0))