2017-06-23 70 views
2

我有兩個元素和一個列表。我必須在第一個元素之前插入第二個元素,每次出現第一個元素時,都會在給定列表的第一個級別中插入第二個元素。在Element2之前插入Element1

遞歸版本:

(defun INSERT-ELEM (E1 E2 L) 
    (cond ((null L) NIL) 
     ((equal E1 (car L)) (cons E2 (INSERT-ELEM E1 E2 (cdr L)))) 
     ((equal E2 (car L)) (cons E1 (INSERT-ELEM E1 E2 (cdr L)))) 
     (t (cons (car L) (INSERT-ELEM E1 E2 (cdr L)))))) 

但什麼是錯的,它改變E1前面的地方,而不是插入E2。 有人可以幫我嗎?

+0

乞討的線((等於E2)做相反的插入,它把'E1'放在E2之前。 – Barmar

+0

@Barmar是什麼?我不明白。 –

回答

3

有兩個問題。

首先,你只能在E1之前插入E2。但行:

((equal E2 (car L)) (cons E1 (INSERT-ELEM E1 E2 (cdr L)))) 

插入E1E2前爲好。你應該刪除它。

第二個問題是,當您進行遞歸調用時,您沒有在結果中包含當前元素。所以你要刪除所有的E1元素。更改爲遞歸調用:

(list* e2 (car l) (insert-elem e1 e2 (cdr l))) 

工作的版本是:

(defun insert-elem (e1 e2 l) 
    (cond ((null l) nil) 
     ((equal e1 (car l)) (list* e2 (car l) (insert-elem e1 e2 (cdr l)))) 
     (t (cons (car l) (insert-elem e1 e2 (cdr l)))))) 

(insert-elem 'a 'b '(1 2 3 a c b d a b e)) 
=> (1 2 3 b a c b d b a b e) 
+0

非常感謝@Barmar ..它幫助了很多! –

2

LOOP變種,用於比較:

(defun insert-before (e1 e2 list) 
    (loop 
    for e in list 
    when (equalp e e1) 
     collect e2 
    collect e)) 

(insert-before 1 0 '(5 4 1 2 1 3 5 1 1 2 3 5 7)) 
=> (5 4 0 1 2 0 1 3 5 0 1 0 1 2 3 5 7) 

MAPCAN變種,爲了好玩:

(defun insert-before (e1 e2 list) 
    (mapcan (lambda (e) 
      (if (equalp e e1) 
       (list e2 e1) 
       (list e))) 
      list))