Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 删除列表中的重复项(序言)_List_Prolog - Fatal编程技术网

List 删除列表中的重复项(序言)

List 删除列表中的重复项(序言),list,prolog,List,Prolog,我对Prolog完全不熟悉,还尝试了一些练习。其中之一是: 编写谓词setInList,OutList 它接受一个任意的输入 列表,并返回一个列表,其中每个 仅显示输入列表的元素 一次 以下是我的解决方案: member(X,[X|_]). member(X,[_|T]) :- member(X,T). set([],[]). set([H|T],[H|Out]) :- not(member(H,T)), set(T,Out). set([H|T],Out) :- me

我对Prolog完全不熟悉,还尝试了一些练习。其中之一是:

编写谓词setInList,OutList 它接受一个任意的输入 列表,并返回一个列表,其中每个 仅显示输入列表的元素 一次

以下是我的解决方案:

member(X,[X|_]).
member(X,[_|T]) :- member(X,T).

set([],[]).
set([H|T],[H|Out]) :-
    not(member(H,T)),
    set(T,Out).
set([H|T],Out) :-
    member(H,T),
    set(T,Out).

我不允许使用任何内置谓词,最好不要使用not/1。问题是,set/2给出了多个相同的解决方案。输入列表中的重复次数越多,得到的解决方案就越多。我做错了什么?提前感谢。

由于Prolog的回溯功能,您将获得多个解决方案。从技术上讲,提供的每个解决方案都是正确的,这就是为什么要生成它。如果您只想生成一个解决方案,则必须在某个点停止回溯。这就是Prolog的用途。你可能会发现,仔细阅读这篇文章会帮助你解决这个问题

更新:对。如果第一个变量在第二个变量中处于多个位置,那么您的成员谓词将以几种不同的方式计算为true

我使用了这个谓词的名称mymember,以避免与GNU Prolog的内置成员谓词冲突。我的知识库现在如下所示:

mymember(X,[X|_]).
mymember(X,[_|T]) :- mymember(X,T).

not(A) :- \+ call(A).

set([],[]).
set([H|T],[H|Out]) :-
    not(mymember(H,T)),
    set(T,Out).
set([H|T],Out) :-
    mymember(H,T),
    set(T,Out).
set([],[]).
set([H|T],[H|T1]) :- subtract(T,[H],T2), set(T2,T1).
所以,mymember1,[1,1,1]。以三种不同的方式计算为真:

| ?- mymember(1, [1, 1, 1]).

true ? a

true

true

no
如果你只想得到一个答案,你就必须用一个切口。将mymember的第一个定义更改为:

解决你的问题


此外,如果愿意,您可以通过自己定义notalmember谓词来避免不完全。选择权归你。

这不需要剪切,但需要更多的行和另一个参数。 如果我在第三行将[H2 | T2]更改为S,它将产生多个结果。我不明白为什么

setb([],[],_).
setb([H|T],[H|T2],A) :- not(member(H,A)),setb(T,T2,[H|A]).
setb([H|T],[H2|T2],A) :- member(H,A),setb(T,[H2|T2],A).
setb([H|T],[],A) :- member(H,A),setb(T,[],A).
set(L,S) :- setb(L,S,[]).

一个更简单且可能更快的解决方案是使用库谓词sort/2,它删除日志n中的重复项。在Yap-prolog和SWIPL中绝对有效,您只需停止prolog的回溯

enter code here
member(X,[X|_]):- !.
member(X,[_|T]) :- member(X,T).

set([],[]).
set([H|T],[H|Out]) :-
   not(member(H,T)),
   !,
set(T,Out).
set([H|T],Out) :-
   member(H,T),
   set(T,Out).

如果集合中元素的顺序不重要,可以使用Tim的支持函数mymember执行此操作:

mymember(X,[X|_]).
mymember(X,[_|T]) :- mymember(X,T).

mkset([],[]).
mkset([T|C], S) :- mymember(T,C),!, mkset(C,S).
mkset([T|C], S) :- mkset(C,Z), S=[T|Z].
例如,-mkset[1,4,1,1,3,4],S将您作为输出:

S = [1, 3, 4]
S = [1, 4, 3]
但是,如果您想要一个元素按列表中的顺序排列的集合,您可以使用:

mkset2([],[], _).
mkset2([T|C], S, D) :- mkset2(C,Z,[T|D]), ((mymember(T,D), S=Z,!) ; S=[T|Z]).
mkset(L, S) :- mkset2(L,S,[]).
此解决方案与上一个示例的输入相同,为您提供:

S = [1, 4, 3]

这一次,元素的顺序与它们在输入列表中的显示顺序相同。

您走在正确的轨道上。。。保持纯洁——这很容易

将具体化的相等谓词=/3和dif/3与if_U3结合使用,如中所实现:

基于这些谓词,我们构建了一个具体化的成员谓词列表\u item\u isMember/3。它在语义上与@false的memberd_truth/3等价。我们重新排列参数顺序,使列表成为第一个参数。这将启用第一个参数索引,防止在memberd_truth/3创建时留下无用的选择点

list_item_isMember([],_,false).
list_item_isMember([X|Xs],E,Truth) :-
   if_(E = X, Truth = true, list_item_isMember(Xs,E,Truth)).

list_set([],[]).
list_set([X|Xs],Ys) :-
    if_(list_item_isMember(Xs,X), Ys = Ys0, Ys = [X|Ys0]),
    list_set(Xs,Ys0).
一个简单的查询显示,所有多余的答案都已消除,目标成功,没有留下任何选择点:

SWI-Prolog的内置谓词subtract/3可以是非单调的,这可能会限制它的使用。列表项减去/3是它的单调变体:

list_item_subtracted([],_,[]).
list_item_subtracted([A|As],E,Bs1) :-
    if_(dif(A,E), Bs1 = [A|Bs], Bs = Bs1),
    list_item_subtracted(As,E,Bs).
list_setB/2与set/2类似,但基于list_item_subtracted/3——而非subtracted/3:

以下查询比较列表设置/2和列表设置/2:


我认为更好的方法是:

set([], []).
set([H|T], [H|T1]) :- subtract(T, [H], T2), set(T2, T1).
例如,-set[1,4,1,1,3,4],S给你作为输出:

S = [1, 3, 4]
S = [1, 4, 3]

将我的答案添加到此旧线程:

notmember(_,[]).
notmember(X,[H|T]):-X\=H,notmember(X,T).

set([],[]).
set([H|T],S):-set(T,S),member(H,S).
set([H|T],[H|S]):-set(T,S),not(member(H,S)).

此解决方案的唯一优点是,它只使用在本书末尾讨论的切分中出现此练习时引入的谓词。我还没有读到关于他们的书。所以,如果这个谓词给出了多个相同的答案,并且所有答案都是正确的,那么从技术上讲,我解决了这个练习:好吧,我的序言已经过时了,我手头也没有环境,但我看不出在这种特殊情况下如何得到多个结果。我假设您使用第一个绑定变量和第二个未绑定变量调用set。在这种情况下,我希望set只在not或member生成多个结果时才为第二个变量生成多个值,我不相信这两个都会。通过一步一步地跟踪评估,看看您的多个结果来自何处,您将获得比我目前能提供给您的更多的洞察,了解正在发生的事情。我现在已经找到并安装了GNU Prolog,它没有not谓词。你能概述一下not谓词是如何定义的吗?谢谢,现在我明白了为什么它会得到多个答案了!:蒂姆,谢谢你的帮助。我学习了运算符\+的实际用法,也因为多个响应而使用了cut运算符。这里的目标是学习prolog,而不是学习如何使用库函数;请注意:这种方法很简单:虽然有一些副作用,
如果你的目标只是找到一个顺序无关紧要的结果列表,那么就使用它:@Pierre LouisGottfrois我在寻找其他东西,但我需要说:没有人通过重新实现糟糕的库谓词来掌握编程语言。难怪大多数学生讨厌序言。@user1812457,他说难怪大多数学生讨厌序言,认为它是拙劣的论点。相反,我想说的是,如果大多数学生确实讨厌Prolog,那么这是一个非常好的信号,表明了对这种编程语言的智力兴趣。为什么在最后的查询中有选择点?似乎memberd_truth/2需要更好的实现。是的,代码是针对SWI Prolog。。。谢谢你重视我的解决方案-@rkta这不是一个优化的解决方案。它可以有效地处理较小的列表,但随着列表长度的增加,搜索空间会变大。我们可以使用累加器对其进行优化。
set([], []).
set([H|T], [H|T1]) :- subtract(T, [H], T2), set(T2, T1).
S = [1, 4, 3]
notmember(_,[]).
notmember(X,[H|T]):-X\=H,notmember(X,T).

set([],[]).
set([H|T],S):-set(T,S),member(H,S).
set([H|T],[H|S]):-set(T,S),not(member(H,S)).
/* Remove duplicates from a list without accumulator */
our_member(A,[A|Rest]).
our_member(A, [_|Rest]):-
    our_member(A, Rest).

remove_dup([],[]):-!.
remove_dup([X|Rest],L):-
    our_member(X,Rest),!,
    remove_dup(Rest,L).
remove_dup([X|Rest],[X|L]):-
    remove_dup(Rest,L).