簡體   English   中英

在Prolog中交換列表的連續項

[英]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.

編輯2015-04-24

這是以前給出的代碼的更直接,有些非優化的變體。

低效率的,但希望有點容易被人類閱讀 像其他變種一樣純潔。

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.

(請通過repeatLudwig閱讀答案。這些都是很好的答案)

修改以刪除舊解決方案中的兩個假設

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.

修改以刪除假設2

如果要查詢conseq_swap(a, e, [a, g, d, e, f], X). 徹底失敗,刪除舊解決方案中的前兩行,這允許原始列表在沒有執行交換時最終作為輸出。

舊解決方案(與相關代碼相同的輸出)

這是使用以下假設編寫的舊解決方案:

  1. 輸入不包含任何無界變量。
  2. 當找不到滿足條件的對時, 按原樣輸出輸入列表 ,類似於問題中的代碼。
% 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM