Prolog 序言在两个单词中找到相似的字母
我有这样的问题,我需要找到由两个单词中的字母组成的最长单词,这些字母的顺序必须与原始单词相同,例如Prolog 序言在两个单词中找到相似的字母,prolog,Prolog,我有这样的问题,我需要找到由两个单词中的字母组成的最长单词,这些字母的顺序必须与原始单词相同,例如xared和pppaed必须返回aed。我不知道如何在Prolog中实现这一点 sl(A, B, C) :- atom_chars(A, Alist), atom_chars(B, Blist), intersection(Alist, Blist, Clist), atom_chars(C, Clist). 试运行: ?- sl(xabred, pppaed, X
xared
和pppaed
必须返回aed
。我不知道如何在Prolog中实现这一点
sl(A, B, C) :-
atom_chars(A, Alist),
atom_chars(B, Blist),
intersection(Alist, Blist, Clist),
atom_chars(C, Clist).
试运行:
?- sl(xabred, pppaed, X).
X = aed.
如果我正确理解了需求,那么请求的是一个谓词,它将(重述)在两个给定字符串中找到最长的子字符串(实际上是原子)。如果在相同的最长长度上有多个,则需要列出所有。这表示结果是一个包含一个或多个单词的列表 这是一个可以做这项工作的刺戳,但是它看起来有点“笨拙”和低效,特别是如果你考虑了很长的字符串:
% Give a list of the longest matching words (substrings)
matchwords(W1, W2, Results) :-
setof(R, matchw(W1, W2, R), RSet), % Collect all the matching substrings
% and their lengths
reverse(RSet, Set), % Order by longest first
highest(Set, Results). % keep only the highest ones
% match atom-string W1 and W2 yielding atom-string Result of length N
matchw(W1, W2, N-Result) :-
atom_chars(W1, A1),
atom_chars(W2, A2),
matchl(A1, A2, R),
length(R, N),
atom_chars(Result, R).
% find a matching sublist between the first two lists
matchl([H|T1], [H|T2], [H|T]) :-
matchl(T1, T2, T).
matchl([H1|T1], [H2|T2], R) :-
H1 \= H2,
( matchl(T1, [H2|T2], R) ; matchl([H1|T1], T2, R) ).
matchl([], _, []).
matchl([_|_], [], []).
% Keep the highest elements at the front of a list of N-W pairs
highest([_-W], [W]).
highest([N1-W1,N2-_|_], [W1]) :-
N1 > N2.
highest([N1-W1,N2-W2|T], [W1|WT]) :-
N1 = N2,
highest([N2-W2|T], WT).
举几个例子:
| ?- matchwords(xabred, pppaed, Matches).
Matches = [aed] ? a
(2 ms) no
| ?- matchwords(abcdef, acbedf, Matches).
Matches = [acef,acdf,abef,abdf] ? a
no
这归结起来就是一个问题。上面的代码并不试图实现本文中提供的强制解决方案。让我们首先找到任何常见的字符子序列(我假设我们正在处理字符列表):
这将生成所有回溯解决方案:
?- common([a, b, c, d], [e, c, d, b], Cs).
Cs = [b]
Yes (0.00s cpu, solution 1, maybe more)
Cs = [c, d]
Yes (0.00s cpu, solution 2, maybe more)
Cs = [c]
Yes (0.00s cpu, solution 3, maybe more)
Cs = [d]
Yes (0.02s cpu, solution 4, maybe more)
Cs = []
Yes (0.03s cpu, solution 5)
您现在可以使用findall/3或setof/3收集所有解决方案,并过滤掉最长的解决方案。或者,下面显示如何修改代码,使其首先返回最长的解决方案:
ordered_common(Xs, Ys, Cs) :-
le_min_length(Xs, Ys, Cs),
common(Xs, Ys, Cs).
le_min_length([_|Xs], [_|Ys], [_|Zs]) :-
le_min_length(Xs, Ys, Zs).
le_min_length(_, _, []).
这样,一旦搜索提供了您喜欢的解决方案,您就可以停止搜索
?- ordered_common([a, b, c, d], [e, c, d, b], Cs).
Cs = [c, d]
Yes (0.00s cpu, solution 1, maybe more)
“abc”和“cba”将产生三种解决方案:“a”、“b”和“c”?在prolog中,您可以使用
atom\u chars(abc[a,b,c])
在atom和它的字符列表之间切换。然后编写谓词来处理元素列表。首先,是的,它将产生a,b,c,然后你需要一个谓词,它接受两个原子字符串并产生一个列表。谓词应该使用atom\u chars
将原子字符串转换为字符列表,然后它可以生成两个列表之间匹配的原子字符列表序列,然后选择最长的列表,最后使用atom\u chars
转换回原子字符串。@mbrach我不知道如何做,我用atom\u chars做了一个列表,但我不知道下一步要做什么。你能给我举个例子吗?谢尔盖,这不一定能给出正确的答案。例如,sl(abcdef,acbedf,L)。
产生,L=abcdef
,而在这种情况下正确的答案是acef
,acdf
,abef
,以及abdf
。我认为,intersection
在这里造成了麻烦,因为它没有强制执行列表顺序(这是一个集合操作)。很好。common/3
可以取代我的matchl/3
。根据字符串的不同,matchl
是较少的推断。例如,如果您使用[a,b,c,d,e,f]
和[a,c,b,e,d,f]
,那么match
大约是common/3
用于查找所有解决方案的推理数量的40%。
?- ordered_common([a, b, c, d], [e, c, d, b], Cs).
Cs = [c, d]
Yes (0.00s cpu, solution 1, maybe more)