[英]Swapping consecutive items of a list in Prolog
我正在尝试编写可以交换列表中两个元素的Prolog代码,但前提是它们彼此连续 。 那是,
conseq_swap(d, e, [a, g, d, e, f], X).
应该给:
X = [a, g, e, d, f].
(d和e是连续的。)
然而,
conseq_swap(a, e, [a, g, d, e, f], X).
应该总是失败(a和e不连续。)
我可以假设一个项目只出现在列表中一次。
我有以下代码,实际上工作正常:
swap_conseq(X, Y, MainList, SwappedList) :-
indexOf(MainList, X, Xpos),
indexOf(MainList, Y, Ypos),
Diff is Ypos - Xpos,
Diff is 1,
Xpos < Ypos,
swap_ordered(X, Y, Xpos, Ypos, MainList, SwappedList).
swap_conseq(X, Y, MainList, SwappedList) :-
indexOf(MainList, X, Xpos),
indexOf(MainList, Y, Ypos),
Diff is Xpos - Ypos,
Diff is 1,
Ypos < Xpos,
swap_ordered(Y, X, Ypos, Xpos, MainList, SwappedList).
swap_ordered(Min, Max, Minpos, Maxpos, MainList, SwappedList) :-
compute_lists(MainList, Min, Minpos, Pre, _),
compute_lists(MainList, Max, Maxpos, _, Post),
append(Pre, [Max, Min], Temp),
append(Temp, Post, SwappedList).
indexOf([Element|_], Element, 1):- !.
indexOf([_|Tail], Element, Index):-
indexOf(Tail, Element, Index1),
!,
Index is Index1+1.
compute_lists(MainList, X, Xpos, A, B) :-
L is Xpos - 1,
append(A, [X | B], MainList),
length(A, L).
但是,仅通过查看代码,我就能知道这是一种可怕的方式-重复,效率低下-只有像我这样的Prolog新手才能编写。
任何建议,以改善这一点将不胜感激!
这是一个逻辑上纯粹的conseq_swap/4
:
conseq_swap(E1,E2,Xs,Ys) :- % use aux predicate w/dif-argument-order
list_item1_item2_swapped(Xs,E1,E2,Ys).
相比于conseq_swap/4
的参数顺序list_item1_item2_swapped/4
被改变,所以第一个参数的索引被启用。 这可以帮助防止不必要的选择点。
list_item1_item2_swapped([],_,_,[]).
list_item1_item2_swapped([X|Xs],E1,E2,Ys) :-
list_prev_item1_item2_swapped(Xs,X,E1,E2,Ys).
我们使用通常称为“滞后”的技术来引用一个引用前一个列表元素的额外参数。 要查看此技术的另一种用法,请查看@mat关于在Prolog列表上实现谓词的其他问题 的答案 。
实际关系由list_prev_item1_item2_swapped/5
定义:
list_prev_item1_item2_swapped([X|Xs],X0,X0,X,[X,X0|Xs]). % stop swapping
list_prev_item1_item2_swapped([X|Xs],X0,E1,E2,[X0|Ys]) :-
dif(X0-X,E1-E2), % state logically pure "not-equal"
list_prev_item1_item2_swapped(Xs,X,E1,E2,Ys).
完成! 现在让我们用SWI-Prolog 7.1.37运行一些查询:
?- conseq_swap(a,e,[a,g,d,e,f],X).
false. % fails, as OP said it should
?- conseq_swap(d,e,[a,g,d,e,f],X).
X = [a,g,e,d,f] ; % succeeds, as OP said it should
false.
?- conseq_swap(d,e,[A,G,D,E,F],X), A=a,G=g,D=d,E=e,F=f.
A = a, G = g, D = d, E = e, F = f, X = [a,g,e,d,f] ; % succeeds
false.
?- conseq_swap(d,e,[a,g,d,e,d,e,f],X).
X = [a,g,e,d,d,e,f] ; % succeeds; only the 1st (d,e) pair is swapped
false.
这是以前给出的代码的更直接,有些非优化的变体。
这是低效率的,但希望有点容易被人类阅读 。 像其他变种一样纯洁。
conseq_swap(X0,X1,[X0,X1|Xs],[X1,X0|Xs]).
conseq_swap(E0,E1,[X0,X1|Xs],[X0|Ys]) :-
dif(X0-X1,E0-E1),
conseq_swap(E0,E1,[X1|Xs],Ys).
相同的查询, 相同的答案:
?- conseq_swap(a,e,[a,g,d,e,f],X).
false.
?- conseq_swap(d,e,[a,g,d,e,f],X).
X = [a,g,e,d,f] ;
false.
?- conseq_swap(d,e,[A,G,D,E,F],X), A=a,G=g,D=d,E=e,F=f.
A = a, G = g, D = d, E = e, F = f, X = [a,g,e,d,f] ;
false.
?- conseq_swap(d,e,[a,g,d,e,d,e,f],X).
X = [a,g,e,d,d,e,f] ;
false.
(请通过repeat和Ludwig阅读答案。这些都是很好的答案)
conseq_swap(E1,E2,[E1,E2|R],[E2,E1|R]).
conseq_swap(E1,E2,[E2,E1|R],[E1,E2|R]).
conseq_swap(E1,E2,[A|RI],[A|RO]) :- conseq_swap(E1,E2,RI,RO).
剪切( (!)/0
)被删除。
?- conseq_swap(a,e,[a,g,d,e,f],X).
false.
?- conseq_swap(d,e,[a,g,d,e,f],X).
X = [a, g, e, d, f] ;
false.
?- conseq_swap(d,e,[D,A,G,E,F],X), A=a,G=g,D=d,E=e,F=f.
false.
?- conseq_swap(d,e,[A,G,D,E,F],X), A=a,G=g,D=d,E=e,F=f.
A = a,
G = g,
D = d,
E = e,
F = f,
X = [a, g, e, d, f] ;
false.
对于有许多可能的交换对的情况,它仅输出一次交换的所有方式。 这个问题假定反正只能有一对。
?- conseq_swap(d,e,[a,g,d,e,d,e,f],X).
X = [a, g, e, d, d, e, f] ;
X = [a, g, d, d, e, e, f] ;
X = [a, g, d, e, e, d, f] ;
false.
如果要查询conseq_swap(a, e, [a, g, d, e, f], X).
彻底失败,删除旧解决方案中的前两行,这允许原始列表在没有执行交换时最终作为输出。
这是使用以下假设编写的旧解决方案:
% Empty list gives empty list
conseq_swap(_,_,[],[]).
% List with single element gives back the same list
conseq_swap(_,_,[A],[A]) :- !.
% If we found the 2 items that need to be swapped, we can swap them.
% We don't check for the rest of the list, due to the
% assumption.
% The cut at the end signals that the rule below do not need to be checked.
conseq_swap(E1,E2,[E1,E2|R],[E2,E1|R]) :- !.
conseq_swap(E1,E2,[E2,E1|R],[E1,E2|R]) :- !.
% We recursively check the rest of the list and append the result.
conseq_swap(E1,E2,[A|RI],[A|RO]) :- conseq_swap(E1,E2,RI,RO).
另一个解决方案(在SWI-Prolog中)将是:
conseq_swap(D, E, L, Z) :-
append([A,[D,E],B], L),
append([A,[E,D],B], Z).
相同的查询,相同的答案:
?- conseq_swap(a,e,[a,g,d,e,f],X).
false.
?- conseq_swap(d,e,[a,g,d,e,f],X).
X = [a, g, e, d, f] ;
false.
?- conseq_swap(d,e,[A,G,D,E,F],X), A=a,G=g,D=d,E=e,F=f.
A = a,
G = g,
D = d,
E = e,
F = f,
X = [a, g, e, d, f] ;
false.
?- conseq_swap(d,e,[a,g,d,e,d,e,f],X).
X = [a, g, e, d, d, e, f] ;
X = [a, g, d, e, e, d, f] ;
false.
(对不起,如果我不能写得那么像“重复”,但我是意大利人)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.