如何从lisp中的字符串列表创建递归嵌套的alists

时间:2018-02-19 12:43:37

标签: lisp common-lisp

我熬夜写这个函数,它接受一个字符串列表并将其转换为一组递归嵌套的alist。我尝试使用pushnew,以便现有的字符串不会重复,但必须创建我自己的重复测试,因为我无法得到pushnew。

显然有一种方法可以使用递归,但是我无法使用它,因为我无法将pushnew的目标部分调用到正确的位置。

我终于以一种愚蠢的方式做到了,但是聪明的方式是什么?

    (defvar vocab '())

(defun place-down ( a b &optional c d e f g)
    (unless (assoc a vocab :test #'equal)
        (pushnew (cons a '()) vocab :test #'equal))
    (unless (assoc b (cdr(assoc a vocab :test #'equal)):test #'equal)
        (pushnew (cons b '()) (cdr(assoc a vocab :test #'equal :test #'equal))))
    (when c
        (unless (assoc c (cdr(assoc b (cdr(assoc a vocab :test #'equal :test #'equal
            )):test #'equal)):test #'equal)
            (pushnew (cons c '()) (cdr(assoc b (cdr(assoc a vocab :test #'equal
             :test #'equal)):test #'equal)))))
    (when d
        (unless (assoc d (cdr(assoc c (cdr(assoc b (cdr(assoc a vocab :test #'equal 
            :test #'equal)):test #'equal)):test #'equal)):test #'equal)
            (pushnew (cons d '()) (cdr(assoc c (cdr(assoc b (cdr(assoc a vocab :test 
                #'equal :test #'equal)):test #'equal)):test #'equal)))))
    (when e
        (unless (assoc e (cdr(assoc d (cdr(assoc c (cdr(assoc b (cdr(assoc a vocab 
            :test #'equal :test #'equal)) :test #'equal)):test #'equal)):test #'equal)):test #'equal)
            (pushnew (cons e '()) (cdr(assoc d (cdr(assoc c(cdr(assoc b (cdr(assoc a vocab 
                :test #'equal :test #'equal)) :test #'equal)):test #'equal)):test #'equal)))))
    (when f
        (unless (assoc f (cdr(assoc e (cdr(assoc d(cdr(assoc c(cdr(assoc b (cdr(assoc a vocab 
            :test #'equal :test #'equal)) :test #'equal)):test #'equal)):test #'equal)):test #'equal))
        :test #'equal)
            (pushnew (cons f '()) (cdr(assoc e (cdr(assoc d(cdr(assoc c(cdr(assoc b (cdr(assoc a vocab 
                :test #'equal :test #'equal)) :test #'equal)):test #'equal)):test #'equal)):test #'equal)))))
    (when g
        (unless (assoc g (cdr(assoc f (cdr(assoc e(cdr(assoc d(cdr(assoc c(cdr(assoc b (cdr(assoc a vocab
         :test #'equal :test #'equal)) :test #'equal)):test #'equal)):test #'equal)):test #'equal))
        :test #'equal)):test #'equal)
            (pushnew (cons g '()) (cdr(assoc f (cdr(assoc e(cdr(assoc d(cdr(assoc c(cdr(assoc b (cdr(assoc a vocab 
                :test #'equal :test #'equal)) :test #'equal)):test #'equal)):test #'equal)):test #'equal)):test #'equal)))))) 

在我说的那些:

*(place-down "this" "is" "it" "the" "life" "we" "live")

* vocab

=> (("this" ("is" ("it" ("the" ("life" ("we" ("live"))))))))

2 个答案:

答案 0 :(得分:3)

示例看起来像REDUCE可以解决的问题。

(defun place-down (&rest strings)
  (reduce (lambda (string accumulator)
            (if accumulator
                (list string accumulator)
                (list string)))
          strings
          :initial-value nil
          :from-end t))
具有显式REDUCE参数的

:initial-value是以最统一的方式调用给定的reduce函数的情况;否则,该函数可以用零或两个参数调用,如果列表只有一个元素,甚至根本不能调用(谢谢@jkiiski)。如果累加器是NIL,我们将其丢弃。测试:

(place-down "this" "is" "it" "the" "life" "we" "live")
=> ("this" ("is" ("it" ("the" ("life" ("we" ("live")))))))

(place-down "this" "is" "it")
=> ("this" ("is" ("it")))

(place-down "this")
=> ("this")

(place-down)
=> NIL

:from-end t参数使操作成为右关联。

答案 1 :(得分:1)

CL-USER 8 > (loop with result = nil
                  for l in (reverse '("this" "is" "it" "the" "life" "we" "live"))
                  do (setf result (list (cons l result)))
                  finally (return result))
(("this" ("is" ("it" ("the" ("life" ("we" ("live"))))))))

CL-USER 9 > (let ((result nil)
                  (list '("this" "is" "it" "the" "life" "we" "live")))
              (dolist (l (reverse list) result)
                (setf result (list (cons l result)))))
(("this" ("is" ("it" ("the" ("life" ("we" ("live"))))))))