2

我想将序言中列表中的元素移动到同一列表中的新位置,类似于剪切和粘贴操作。

例如,如果我有列表 [1,2,3,4,5]

我想要类似的东西:

move(List, D1, D2, D3, Newlist)

List = 原始列表,D1 = 从哪个元素,D2 = 到列表的哪个元素,D3 列表中的目的地。

一个例子:

move([1,2,3,4,5,6,7,8,9], 1, 3, 5, NewList) :- (Implementation).

NewList = [4,5,1,2,3,6,7,8,9].

我在 D3 > D2 时做了这个,在 D2 < D3 时做了类似的事情,但我认为我做的不对。

% Move D3 > D2 & D2
move([X|L], D1, D2, D3, Resultado) :-
    movevalue([X|L], D1, D2, Z),
    moveinsert([X|L], Z, D3, ParteB),
    primerapartel([X|L], D3, PrimeraParte),
    deleting(PrimeraParte, D1, D2, ParteA),
    append(ParteA, ParteB, Resultado),
    !.

movevalue([X|L], D1, D2, Z) :-
    D1 > 1,
    E1 is D1 - 1,
    E2 is D2 - 1,
    movevalue(L, E1, E2, Z),
    !.
movevalue([X|L], 1, D2, [X|Z]) :-
    D2 > 0,
    E2 is D2 - 1,
    movevalue(L, 1, E2, Z).
movevalue([X|L], 1, 0, Z) :-
    Z = [].

moveinsert([X|L], Z, D3, Resultado) :-
    D3 > 1,
    E3 is D3 - 1,
    moveinsert(L, Z, E3, Resultado),
    !.
moveinsert([X|L], Z, 1, Resultado) :-
    append(Z,L,Resultado).

%append([X],Z,Resultado2)
%Primera parte L
primerapartel(_, 0, Resultado) :-
    Resultado = [], !.
primerapartel([X|L], N, [X|Resultado]) :-
    N > 0,
    N1 is N - 1,
    primerapartel(L, N1, Resultado),
    !.

deleting(Lista, D1, D2, Resultado) :-
    deletingizq(Lista, D1, D2, ResultadoA),
    deletingder(Lista, D1, D2, ResultadoB),
    append(ResultadoA, ResultadoB, Resultado),
    !.

deletingizq([Princi|Pal], D1, D2, [Princi|Resultado]) :-
    D1 > 1,
    E1 is D1 - 1,
    E2 is D2 - 1,
    deletingizq(Pal, E1, E2, Resultado).
deletingizq([X|L], 1, D2, Resultado) :-
    D2 > 1,
    E2 is D2-1,
    deletingizq(L, 1, E2, Resultado).
deletingizq([X|L], 1, 1, Resultado) :-
    Resultado = [].

deletingder([Princi|Pal], D1, D2, Resultado) :-
    D1 > 1,
    E1 is D1 - 1,
    E2 is D2 - 1,
    deletingder(Pal, E1, E2, Resultado).
deletingder([X|L], 1, D2, Resultado) :-
    D2 > 1,
    E2 is D2 - 1,
    deletingder(L, 1, E2, Resultado).
deletingder([X|L], 1, 1, Resultado) :-
    Resultado = L.
4

1 回答 1

2

您已经发现 Prolog 列表不容易通过索引处理的困难方式。

为了使问题更具说明性,从而可以在 Prolog 中解决,我将在长度/2 和nth1 /3 的帮助下将索引与映射分开。

首先,我们知道 Result 将具有与 List 相同的长度。强制执行:

move(List, Start, Stop, Target, Result) :-
    length(List, N),
    length(Result, N),
    move_elements(1, N, List, Start, Stop, Target, Result).

移动元素需要将索引从 List 映射到 Result,我们必须对每个元素执行以下操作:

/* edit: see the code below - this is buggy    
move_elements(I, N, _List, _Start, _Stop, _Target, _Result) :-
    I =:= N + 1.
move_elements(I, N, List, Start, Stop, Target, Result) :-
    nth1(I, List, E),
    index_map(I, Start, Stop, Target, P),
    nth1(P, Result, E),
    J is I + 1,
    move_elements(J, N, List, Start, Stop, Target, Result).
*/
move_elements(I, N, List, Start, Stop, Target, Result) :-
    I =< N,
    nth1(I, List, E),
    index_map(I, Start, Stop, Target, P),
    nth1(P, Result, E),
    J is I + 1,
    !, move_elements(J, N, List, Start, Stop, Target, Result).
move_elements(_I, _N, _List, _Start, _Stop, _Target, _Result).

我们留下了困难的部分:index_map必须做一些算术,在可用位置之间进行调整。到目前为止,我认为这个问题有点未明确。这只是基本案例,涵盖了您的测试查询:

index_map(I, Start, Stop, Target, P) :-
    I >= Start,
    I =< Stop,
    P is Target - (Stop - Start + 1) + I.
index_map(_I, _Start, _Stop, _Target, _P).

您应该添加更多测试以指定更多约束,但请注意 index_map/5 的最后一个子句允许Prolog 搜索匹配元素(通过nth1(P, Result, E)),从而以简单的方式完成映射。

编辑:在foreach /2 的帮助下,我们可以避免循环

move(List, Start, Stop, Target, Result) :-
    length(List, N),
    length(Result, N),
    foreach(nth1(I, List, E), assign(I, E, Start, Stop, Target, Result)).

assign(I, E, Start, Stop, Target, Result) :-
    index_map(I, Start, Stop, Target, P),
    nth1(P, Result, E).
于 2013-06-29T08:18:11.907 回答