Prolog 检查列表之间的数字是否相等?

Prolog 检查列表之间的数字是否相等?,prolog,clpfd,Prolog,Clpfd,什么是检查序言中列表之间有多少相同结尾数字的有效方法? 例如,我们有Lista=[443223453243]和Listb=[33453232] 在这两个列表中,我们有4432和3232,它们有2个相同的结束数字和33452345,它们有3个相同的结束数字。3243232有相同的2个起始数字,但我不认为这是有效的。我以最慢的方式解决了这个问题,通过检查每个Lista的数量和每个Listb的数量,但这是非常慢的。我怎样才能更有效地解决这个问题 编辑1:我对答案代码进行了一些更改,我设法找到了相同的

什么是检查序言中列表之间有多少相同结尾数字的有效方法?

例如,我们有
Lista=[443223453243]
Listb=[33453232]

在这两个列表中,我们有44323232,它们有2个相同的结束数字33452345,它们有3个相同的结束数字。3243232有相同的2个起始数字,但我不认为这是有效的。我以最慢的方式解决了这个问题,通过检查每个
Lista
的数量和每个
Listb
的数量,但这是非常慢的。我怎样才能更有效地解决这个问题


编辑1:我对答案代码进行了一些更改,我设法找到了相同的数字和剩余的子树,但是我无法将它们组合在一起,以便找到一个列表中元素具有相同数字的数字。你能帮我继续吗

相同的结尾(Tree,N/*4904*/,N-Len-Last):-
原子字符(N,Digs),
反向(Digs、RDIG),
相同的结尾1(RDigs,树,[],鳍,0,透镜),
pow2(镜头,Res1),
Res是Res1-1,
Len=Res,
最后一个=鳍。
相同的结尾1([],[当前,财务,长,长)。
相同的结尾1([Dig | Digs],树,电流,鳍,Len,Len2):-
(选择(挖掘子树、树)->
(成功(Len,Len1),追加([Dig],Curr,Currn),
相同的结尾1(挖掘、子树、当前、Fin、Len1、Len2))
; 
Len2=Len,
Fin=Curr树
).

编辑2:对于@gusbro答案的最后建议,我创建了以下代码

ssame_结尾(L1,[],Curr,Final):-Final=Curr。
ssame_结尾(L1、L2、Curr、Final):-
构建树(L1,树),
头部(L2,H),
尾部(L2,T),
findall(Res,相同的_结尾(Tree,H,Res),结尾),
附加(当前、结尾、当前1),
ssame_结尾(L1,T,Curr1,Final)。
头([A | |,]A)。
尾巴([u124; A],A)。
pow2(X,Z):-Z是2**X。
相同的结尾(树,N,N-Len/LItems):-
原子字符(N,Digs),
反向(Digs、RDIG),
相同的结尾1(RDigs,Tree,0,Len,SubTree),
长度(SDigs,Len),
附加(SDigs、RDigs、,
反向(SDigs、RSDigs),
相同的后缀2(子树,RSDigs,[],LItems)。
相同的结尾([],子树,Len,Len,SubTree1):-
子树=[]->SubTree1=[[]];子树1=子树。
相同的结尾1([Dig | Digs],树,Len,Len2,子树):-
(选择(挖掘子树、树、第三个)->
(such(Len,Len1),same_ending1(Digs,DigSubTree,Len1,Len2,SubTree),same_ending1(Digs,Third,Len1,Len2,SubTree));
Len2子树=Len树
).

我按照建议使用findall来组合给出的所有答案,我认为这一部分是正确的。然后我使用select,如果我们有树[1-[2-[3,4]]我们需要1,2,3和1,2,4。如果我们有数字5321,第三个参数也会给我们124。但是我使用它的方式并没有产生预期的结果。我做错了什么?

你可以为第一个列表建立一个反向数字树,然后为第二个列表中的每个反向项遍历该树。这可能更有效如果列表中有许多项,请输入

same_endings(L1, L2, Endings):-
  build_tree(L1, Tree),
  maplist(same_ending(Tree), L2, Endings).

same_ending(Tree, N, N-Len):-
  atom_chars(N, Digs),
  reverse(Digs, RDigs),
  same_ending1(RDigs, Tree, 0, Len).

same_ending1([], _, Len, Len).
same_ending1([Dig|Digs], Tree, Len, Len2):-
  (select(Dig-SubTree, Tree, _) ->
    (
        succ(Len, Len1), 
        same_ending1(Digs, SubTree, Len1, Len2)
    ) ;
    Len2=Len
  ).

build_tree(L, Tree):-
  foldl(add_tree, L, [], Tree).

add_tree(N, Tree, NTree):-
  atom_chars(N, Digs),
  reverse(Digs, RDigs),
  add_tree1(RDigs, Tree, NTree).

add_tree1([], Tree, Tree).
add_tree1([Dig|Digs], Tree, [Dig-SubTree1|Tree1]):-
  (select(Dig-SubTree, Tree, Tree1) -> true; SubTree-Tree1=[]-Tree),
  add_tree1(Digs, SubTree, SubTree1).
测试样本:

?- same_endings( [4432,2345,3243] , [3345,3232], Endings).
Endings = [3345-3, 3232-2].
您可以稍微修改此代码以获得具有相同结尾的实际项目


稍微修改一下上面的代码,您还可以列出第一个列表中的实际数字,这些数字在第二个列表中的每个项目上都有相同(最大)的结尾:

same_endings(L1, L2, Endings):-
  build_tree(L1, Tree),
  maplist(same_ending(Tree), L2, Endings).

same_ending(Tree, N, N-Len/LItems):-
  atom_chars(N, Digs),
  reverse(Digs, RDigs),
  same_ending1(RDigs, Tree, 0, Len, SubTree),
  length(SDigs, Len),
  append(SDigs, _, RDigs),
  reverse(SDigs, RSDigs),
  same_ending2(SubTree, RSDigs, [], LItems).

same_ending1([], SubTree, Len, Len, SubTree).
same_ending1([Dig|Digs], Tree, Len, Len2, SubTree):-
  (memberchk(Dig-DigSubTree, Tree) ->
    (
        succ(Len, Len1), 
        same_ending1(Digs, DigSubTree, Len1, Len2, SubTree)
    ) ;
    Len2-SubTree=Len-Tree
  ).

same_ending2([], _, LItems, LItems).
same_ending2([Dig-DigSubTree|SubTree], Digs, MItems, LItems):-
  (Dig=endmarker -> 
    (
        number_chars(Item, Digs), 
        NItems=[Item|MItems]
    ) ;
    same_ending2(DigSubTree, [Dig|Digs], MItems, NItems)
  ), 
  same_ending2(SubTree, Digs, NItems, LItems).

build_tree(L, Tree):-
  foldl(add_tree, L, [], Tree).

add_tree(N, Tree, NTree):-
  number_chars(N, Digs),
  reverse(Digs, RDigs),
  add_tree1(RDigs, Tree, NTree).

add_tree1([], Tree, [endmarker-[]|Tree]).
add_tree1([Dig|Digs], Tree, [Dig-SubTree1|Tree1]):-
  (select(Dig-SubTree, Tree, Tree1) -> true; SubTree-Tree1=[]-Tree),
  add_tree1(Digs, SubTree, SubTree1).
测试用例:

?- same_endings( [4432,2345,3243] , [3345,3232], Endings).
Endings = [3345-3/[2345], 3232-2/[4432]].
?- same_endings( [4432,2345,3243,2195345,2345] , [3345,3232,19232,2195345], Endings).
Endings = [3345-3/[2195345, 2345, 2345], 3232-2/[4432], 19232-2/[4432], 2195345-7/[2195345]].
当一个项目没有共享任何结尾数字时,没有特殊处理,在这种情况下,代码只会吐出整个列表


如果您想获得至少有一个匹配结尾数字的所有项目,只需将过程
same_endings
same_endings 1
更改为以下步骤:

same_endings(L1, L2, Endings):-
  build_tree(L1, Tree),
  findall(Ending, (member(N, L2), same_ending(Tree, N, Ending)), Endings).

same_ending1([], SubTree, Len, Len, SubTree).
same_ending1([Dig|Digs], Tree, Len, Len2, SubTree):-
  (select(Dig-DigSubTree, Tree, RestTree) ->
    ( 
     (
       Len\=0, 
       RestTree \= [], 
       Len2=Len, 
       SubTree=RestTree
     ) ;
     (
       succ(Len, Len1), 
       same_ending1(Digs, DigSubTree, Len1, Len2, SubTree)
     )
    ) ;
    Len2-SubTree=Len-Tree
  ).
shared_tail_len_atom(A,B,N,S):-
亚_原子(A,u,N,0,S),
N> =1%,提高此值以减少开销
亚原子(B,N,0,S)。
相同的结尾(As、Bs、Es):-
一组(N-ab(A,B),
聚合(
最大值(C),
(成员(A,As),
成员(B,Bs),
共享尾长原子(A,B,C,S)
),N),Es)。
您可以尝试这个简单的代码段。sub_atom/5它是一个ISO Prolog内置代码,但它与数字一起工作的事实可能是一个SWI Prolog扩展

?-相同的结尾(参见[123223333],[423433],结尾)。
结尾=[1-ab(123433),1-ab(223433),1-ab(333423),2-ab(123423),2-ab(223423),2-ab(333433)]。

我编辑了这个问题,因为我正在修整以获得具有相同结尾的实际项目,但我有一个困难:感谢编辑,如果3345有两个相同的结尾数字和另一个数字,而不仅仅是3@Vaas:此算法显示具有最大“相同结尾”的数字。如果您想显示其他数字,您可以更改
相同的\u ending1
来添加其他数字。我已经尝试了几天了,您能给我一个提示吗?我正在修改此代码,问题是程序“继续”直到树上不再有相等的数字。但是我找不到一种方法来添加相等数字小于最大值的数字,因为如果每次它找到一个相等的数字时我都停止它,我们将有许多重复的数字。例如,如果第一个列表是[443223453221953452345995],那么在结果中我应该有[3345-3]/[219534523452345],3345-1/[9995],…],但他们似乎不可能以这种方式编写代码。我错了吗?它会得到“列表之间有多少相等的结尾数字”,按长度排序