使用Lisp或PROLOG从列表中删除元素的外观

时间:2011-08-17 21:14:19

标签: lisp prolog

我必须使用LISP或PROLOG删除列表中元素的外观。

这是一些例子。

输入:'(5 2(3 5(3)5(4 2(2 4)))5 2)

输出:'(5 2(3()5(4(2))))

输出列表的结构保持不变。

感谢您的建议,

3 个答案:

答案 0 :(得分:2)

由于这似乎是一项功课,我将仅提供指向解决方案的指针:

  • 查看Common Lisp中的REMOVE-IF谓词。 (它可能不会做你需要的一切......)
  • 构建一个递归的walker。
  • 考虑如何来回传递状态。

顺便说一句,我强烈建议您发布您的工作片段并提出具体问题。像上面这样的普遍问题似乎表明你想要一个解决方案放在你的腿上。

好的,这不是功课。我在智力上引起了人们的兴趣。我解决了。

这是一个递归的步行者。如果您的Lisp执行TCO,它应该可以转换为TCO。

你可以在一个循环中完成它,但这需要维护一个堆栈列表来处理“进入列表”的情况。

我没有声称是惯用的解决方案。


(defparameter input '(5 2 (3 5 (3) 5 (4 2 (2 4))) 5 2))

(defparameter output '(5 2 (3 () 5 (4 (2)))))

(defun remove-every-other-appearence (list &optional (hash-table nil))
  (when list                             ; termination condition
    ;(format t "~%~a~&" list)
    (unless hash-table                     ; if it's the first time
      ;(format t "creating hash table~&")
      (setf hash-table (make-hash-table))) ; create a hash table
    (let ((eut (car list)))                ; element under test
      ;(format t "eut: ~a~&" eut)
      (cond
        ((consp eut)                      ;Recursion time, it's a list.
         ;(format t "Recursing~&")
         (cons
          (remove-every-other-appearence eut hash-table)
          (remove-every-other-appearence (cdr list) hash-table)))
        (t                                ;Otherwise...
                                        ; Increment seen counter by 1
         (setf (gethash eut hash-table 0) 
               (1+ (gethash eut hash-table 0)))
         (cond
           ((evenp (gethash eut hash-table))
             (remove-every-other-appearence (cdr list) hash-table))
                                        ;ignore the element
           ((oddp (gethash eut hash-table))
                                        ; if this is the odd occurance
                                        ;cons the element back onto the rest of the list
            (cons eut (remove-every-other-appearence (cdr list) hash-table)))           
           (t
            (error "This integer is neither even nor odd. We're in trouble"))))))))

* input

(5 2 (3 5 (3) 5 (4 2 (2 4))) 5 2)
* (remove-every-other-appearence input)

(5 2 (3 NIL 5 (4 (2))))
* output

(5 2 (3 NIL 5 (4 (2))))

答案 1 :(得分:0)

FWIW,你的问题陈述还不清楚。

正如我理解这个问题,问题是你有一个任意的“树”,其非叶节点是列表,叶子节点是其他东西。一份“清单清单”。您希望将其视为叶节点的逻辑平面序列,对其进行迭代并删除所有其他叶节点,而不用更改“树”的整体形状,例如唯一改变的是从任何给定节点悬挂的叶子数量。

由此,给出以下输入,您将意识到相应的输出:

input:  []
output: []

input:  [a,b,c,d]
output: [a,c]

input:  [a,[],b,c,d]
output: [a,[],c]

input:  [a,[b],c,d]
output: [a,[],c]

input:  [a,[b,c,d,e],f,g]
output: [a,[c,e],g]

input:  [a,[b,[],[c,d,[e,f,g],h],i],j]
output: [a,[[],[c,[e,g]],i]]

这是一个[未经测试的] prolog解决方案。在其中,我只保留两个状态keepremove,并根据需要在它们之间切换。你得到奇数/偶数免费:它只取决于你启动机器的状态。

应该注意的是,如果传入的数据结构包含任何未绑定/非统一变量,则与获得正确结果不同。不需要的统一会导致问题。需要添加Guard子句以正确处理它们。

% ====================
% The public interface
% ====================
remove_even( Xs , Ys ) :- remove_every_other_node( keep   , _ , Xs , [] , Ys ).
remove_odd(  Xs , Ys ) :- remove_every_other_node( remove , _ , Xs , [] , Ys ).

%------------------
% The core iterator
%------------------
remove_every_other_node( S , S , [] , T , List ) :-
  reverse(T,List)
  .
remove_every_other_node( S , N , [X|Xs] , T , List ) :-
  process_node( S, S1 , X , T , T1 ) ,
  remove_every_other_node( S1 , N , Xs , T1 , List )
  .

%----------------------
% The list node handler
%----------------------
process_node( S , S , []     , T , [[]|T] ).
process_node( S , N , [X|Xs] , T , [L1|T] ) :-
  remove_every_other_node( S , N , [X|Xs] , [] , L1)
  .
process_node( keep   , remove , X , T , [X|T] ).
process_node( remove , keep   , X , T , T     ).

答案 2 :(得分:0)

(defun rea (tree)
  (let ((table (make-hash-table)))
    (labels ((fn (x)
               (unless (and x (atom x) (evenp (incf (gethash x table 0))))
                 (list (if (atom x) x (mapcan #'fn x))))))
      (car (fn tree)))))