从列表中删除元素而不删除所有重复项

时间:2013-01-22 09:54:17

标签: prolog

我想从列表中删除元素但是如果我这样做:

deletelist([3,1,2,3,4], [3], [3,1,2,4]) 

如何只删除3并且没有得到这个答案:

deletelist([3,1,2,3,4], [3], [1,2,4])

谢谢!

2 个答案:

答案 0 :(得分:2)

select / 3它是一个有用的内置版,经常用于generate and test,您可以用来删除元素:

?- select(3,[3,1,2,3,4],L).
L = [1, 2, 3, 4] ;
L = [3, 1, 2, 4] ;
false.

每次调用都会删除匹配项,然后您就可以控制所需的行为

修改

删除第二个列表中的所有元素:

deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
    select(D, With, WithoutD),
    deletelist(WithoutD, Ds, Without).

请注意,如果在列表中找不到任何要删除的元素,则会失败。为避免这种情况,请应用'if .. then .. else ..'

deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
    (  select(D, With, WithoutD)
    -> deletelist(WithoutD, Ds, Without)
    ;  deletelist(With, Ds, Without)
    ).

现在,deletelist / 3不会枚举所有可能的删除。它承诺第一个发现。为了恢复最初的行为,即给出所有不同删除的bactracking,需要一个效率较低的过程:

deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
    select(D, With, WithoutD),
    deletelist(WithoutD, Ds, Without).
deletelist(With, [D|Ds], Without) :-
    \+ select(D, With, _),
    deletelist(With, Ds, Without).

答案 1 :(得分:1)

如果您想在列表中只获取唯一值 - 请使用函数list_to_set/2

list_to_set([3,1,2,3,4],X)提供X = [3, 1, 2, 4].

修改

因此gnu prolog没有内置谓词list_to_set。你必须自己写。 为此,您必须定义 set 概念。什么是set of list? Set应具有以下属性:

  • 设置大小必须小于或等于列表大小。
  • Set的所有成员必须是List的成员。
  • List的所有成员必须是Set的成员。
  • Set不得包含重复值。

基于这些假设,您可以像这样编写set_from_list谓词:

elem_unique(Elem, List) :-
  delete(List, Elem, ListWithoutElem),
  length(List, OrgLength),
  length(ListWithoutElem, DelLength),
  DelLength + 1 =:= OrgLength.

nth_elem_isUnique(N, List) :-
  nth1(N, List, Elem),
  elem_unique(Elem, List).

nth_elemOfList1_isMemberOfList2(N, List1, List2) :-
  nth1(N, List1, Elem),
  member(Elem, List2).

elements_from_nth_areUnique(N, List) :-
  (length(List, Len),
  N > Len)    %stoping condition for recursion
  ;
  (nth_elem_isUnique(N, List),
  M is N + 1,
  elements_from_nth_areUnique(M, List)   %recursion part
  ).

listIsUnique(List) :-
  elements_from_nth_areUnique(1, List).

elements_from_nth_inList1_areMembersOfList2(N, List1, List2) :-
  (length(List1, Len),
  N > Len)    %stoping condition for recursion
  ;
  (nth_elemOfList1_isMemberOfList2(N, List1, List2),
  M is N + 1,
  elements_from_nth_inList1_areMembersOfList2(M, List1, List2)  %recursion part
  ).

list2containsList1(List1, List2) :-
  elements_from_nth_inList1_areMembersOfList2(1, List1, List2).

set_from_list(Set, List) :-
  length(Set, LenSet),
  length(List, LenList),
  LenSet =< LenList,
  list2containsList1(List, Set),
  list2containsList1(Set, List),
  listIsUnique(Set),
  !.

因此,在致电set_from_list(Set, [3,1,2,3,4])后,您将获得Set = [3,1,2,4]