将列表1中的特定数字与列表2中的特定数字进行交换

时间:2015-06-19 04:15:56

标签: list prolog predicate

我最近一直在刷一些Prolog。我有点喜欢提出随机问题来尝试解决然后解决它们。这个问题非常艰难,我不会放弃一个我打算解决的问题。

问题:我想创建一个谓词,它将有2个预定列表,2个数字要交换,然后在交换完成后输出列表。

进一步说明:我希望从列表1中找到一个特定的唯一编号,然后使用列表2中的特定唯一编号交换它,以便如果我有2名单... [7,2,7,8,5]和[1,2,3,8,7,9,8],然后给出谓词2个数字(只说8和7),然后是数字8和数字7将在列表之间交换 IF和ONLY IF 数字8在第一个列表中,数字7在第二个列表中。 (它将忽略第二个列表中的8和第一个列表中的7)。

带有预期答案的示例查询:

?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8],8,7,X,Y).
X = [7,2,7,7,5], Y = [1,2,3,8,8,9,8].

我有点陷入困境:

bothSwap([],L2,N1,N2,[],L2).
bothSwap(L1,[],N1,N2,L1,[]).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 == N2, bothSwap(T1,T2,N1,N2,D1,D2), append(D1,[H2],X), append(D2,[H1],Y).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 =\= N2, bothSwap([H1|T1],T2,N1,N2,D1,D2).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 =\= N1, H2 == N2, bothSwap(T1,[H2|T2],N1,N2,D1,D2).

有没有聪明的人愿意和我一起解决这个问题? :)

4 个答案:

答案 0 :(得分:5)

想象一下,如果我们能够"希望"这个问题会变得多么容易。对于要在所需元素出现时拆分的列表,如下所示:

?- splitsies([1,2,3,4,5,6,7,8], 4, Prefix, Suffix).
Prefix = [1, 2, 3],
Suffix = [5, 6, 7, 8] ;
猜猜是什么? :) append/3可以做到这一点:

% splitsies is true if X splits list into a prefix/suffix pair.
splitsies(List, X, Start, Finish) :-
    append(Start, [X|Finish], List).

现在问题看起来很简单了!

bothSwap(Left, Right, A, B, AfterLeft, AfterRight) :-
    % break up the inputs
    splitsies(Left,  A, LPre, LPost),
    splitsies(Right, B, RPre, RPost),

    % glue together the outputs (note that A and B are switched)
    splitsies(AfterLeft,  B, LPre, LPost),
    splitsies(AfterRight, A, RPre, RPost).

我不会假装这种解决方案很有效......但是当你输入它时,你最好戴上烤箱手套。哦,看看这个:

?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8], X, Y, [7,2,7,7,5], [1,2,3,8,8,9,8]).
X = 8,
Y = 7 ;
false.

答案 1 :(得分:4)

让我们开始,你的意思是交换。

swap(X0,X, S0,S) :-
   if_(X0 = S0, S = X, S = S0).

bothSwap0(Xs0, Ys0, X0,X, Xs,Ys) :-
   maplist(swap(X0,X), Xs0,Xs),
   maplist(swap(X,X0), Ys0,Ys).

if_( C_1, Then_0, Else_0) :-
   call(C_1, Truth),
   functor(Truth,_,0),  % safety check
   ( Truth == true -> Then_0 ; Truth == false, Else_0 ).

=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
   dif(X, Y).

现在你想要一个特定的条件 - 目前尚不清楚如何应用它。我看到两种解释:

bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
   memberd(X0, Xs0),
   memberd(X, Ys0),
   maplist(swap(X0,X), Xs0,Xs),
   maplist(swap(X,X0), Ys0,Ys).

这意味着如果两个元素没有出现在各自的列表中,bothSwap/6将失败。

另一种解释可能是你想要的,否则列表保持不变。为了表达这一点(以纯粹的单调方式):

bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
   if_( ( memberd_t(X0, Xs0), memberd_t(X, Ys0) ),
        ( maplist(swap(X0,X), Xs0,Xs), maplist(swap(X,X0), Ys0,Ys) ),
        ( Xs0 = Xs, Ys0 = Ys) ).

memberd_t(E, Xs, T) :-
   list_memberd(Xs, E, T).

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

','( A_1, B_1, T) :-
   if_( A_1, call(B_1, T), T = false ).

答案 2 :(得分:1)

由于Prolog是描述性语言(也就是说,我们描述构成解决方案的内容并让Prolog解决它),如果我正确理解您的问题陈述,这样就足够了:

both_swap(L1, L2, A, B, S1, S2 ) :- % to do the swap,
  memberchk(A,L1) ,                 % - L1 must contain an A
  memberchk(B,L2) ,                 % - L2 must contain a B
  replace(L1,A,B,S1) ,              % - replace all As in L1 with a B
  replace(L2,B,A,S2)                % - replace all Bs in L2 with an A
  .                                 % Easy!

replace([],_,_,[]) .                % if the list is empty, we're done.
replace([H|T],A,B,[S|Ss]) :-        % otherwise...
  ( H = A -> S=B ; S=H ) ,          % - do the swap (if necessary),
  replace(T,A,B,Ss)                 % - and recurse down
  .                                 % Also easy!

答案 3 :(得分:1)

这复制了使用splitsies/4

的实现
swap_two(A,B,C,D,E,F) :-
    nth0(I1,A,C,L1),
    dif(A,L1),
    nth0(I2,B,D,L2),
    dif(B,L2),
    nth0(I1,E,D,L1),
    nth0(I2,F,C,L2).