Вот предикат для разделения списка на:
- a "передний список"
Front
- элемент в позиции N (на основе 0),
Element
- «черный список»
Back
... так, чтобы исходный список L
можно было изменить с помощью:
append([Front,[Element],Back],L).
Код
% split_list(+List, +Index, Element, Front, Back)
split_list([L|Lr], N, El, [L|Front], Back) :-
N>0,!,
Nm is N-1,
split_list(Lr,Nm,El,Front,Back).
split_list([L|Lr], 0, L, [], Lr).
Это действительно трудно читать.
Тесты
:-begin_tests(split_list).
test(empty0,[fail]) :- split_list([],0,_,_,_).
test(empty1,[fail]) :- split_list([],1,_,_,_).
test(oorange,[fail]) :- split_list([a,b],2,_,_,_).
test(oorange,[fail]) :- split_list([a,b],-1,_,_,_).
test(trivial1) :- split_list([a,b,c],0,a,[],[b,c]).
test(trivial2) :- split_list([a,b,c],1,b,[a],[c]).
test(trivial3) :- split_list([a,b,c],2,c,[a,b],[]).
tt(L,X) :-
split_list(L,X,Element,Front,Back),
format("~w ==> ~w ~w ~w\n",[L,Front,Element,Back]),
append([Front,[Element],Back],L).
test(long1) :-
L=[a,b,c,d,e,f,g,h,i,j,k,l],
length(L,Llen),
Nmax is Llen-1,
foreach(between(0,Nmax,X),tt(L,X)).
:-end_tests(split_list).
Мы запускаем выше:
?- run_tests(split_list).
% PL-Unit: split_list .......
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [] a [b,c,d,e,f,g,h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a] b [c,d,e,f,g,h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b] c [d,e,f,g,h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c] d [e,f,g,h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d] e [f,g,h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e] f [g,h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e,f] g [h,i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e,f,g] h [i,j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e,f,g,h] i [j,k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e,f,g,h,i] j [k,l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e,f,g,h,i,j] k [l]
[a,b,c,d,e,f,g,h,i,j,k,l] ==> [a,b,c,d,e,f,g,h,i,j,k] l []
. done
% All 8 tests passed
true.
Хорошо, так что все работает.
Но:
- Эффективно ли это?
- Почему бы это не сделать, например, в
library(lists)
? - Может быть, это какой-то косвенный способ сделать это?
Приложение
Предикат едва читаем.
Как насчет тактического использования диктов?
split_list(L,N,Elem,Front,Back) :-
split_list(_{list: L, index: N, element: Elem, front: Front, back: Back}).
split_list(
_{list: [L|Lr],
index: N,
element: El,
front: [L|Front],
back: Back}) :-
N>0,!,
Nm is N-1,
split_list(
_{list: Lr,
index: Nm,
element: El,
front: Front,
back: Back}).
split_list(
_{list: [L|Lr],
index: 0,
element: L,
front: [],
back: Lr}).
Более разборчиво? Точно сказать не могу. Но, скорее всего, будет медленнее.