Prolog List Exercises: Solutions & Explanations

Prolog List Exercises

1.01 (*): Find the last element of a list

Predicate: my_last(X,L) – X is the last element of the list L.
Arguments: (element,list) (?,?)
Note: last(?Elem, ?List) is predefined

my_last(X,[X]).
my_last(X,[_|L]) :- my_last(X,L).

1.02 (*): Find the last but one element of a list

Predicate: last_but_one(X,L) – X is the last but one element of the list L.
Arguments: (element,list) (?,?)

last_but_one(X,[X,_]).
last_but_one(X,[_,Y|Ys]) :- last_but_one(X,[Y|Ys]).

1.03 (*): Find the K’th element of a list

The first element in the list is number 1.
Predicate: element_at(X,L,K) – X is the K’th element of the list L.
Arguments: (element,list,integer) (?,?,+)
Note: nth1(?Index, ?List, ?Elem) is predefined

element_at(X,[X|_],1).
element_at(X,[_|L],K) :- K > 1, K1 is K - 1, element_at(X,L,K1).

1.04 (*): Find the number of elements of a list

Predicate: my_length(L,N) – the list L contains N elements.
Arguments: (list,integer) (+,?)
Note: length(?List, ?Int) is predefined

my_length([],0).
my_length([_|L],N) :- my_length(L,N1), N is N1 + 1.

1.05 (*): Reverse a list

Predicate: my_reverse(L1,L2) – L2 is the list obtained from L1 by reversing the order of the elements.
Arguments: (list,list) (?,?)
Note: reverse(+List1, -List2) is predefined

my_reverse(L1,L2) :- my_rev(L1,L2,[]).

my_rev([],L2,L2) :- !. my_rev([X|Xs],L2,Acc) :- my_rev(Xs,L2,[X|Acc]).

1.06 (*): Find out whether a list is a palindrome

A palindrome can be read forward or backward; e.g. [x,a,m,a,x].
Predicate: is_palindrome(L) – L is a palindrome list.
Arguments: (list) (?)

is_palindrome(L) :- reverse(L,L).

1.07 (): Flatten a nested list structure

Predicate: my_flatten(L1,L2) – the list L2 is obtained from the list L1 by flattening; i.e., if an element of L1 is a list then it is replaced by its elements, recursively.
Arguments: (list,list) (+,?)
Note: flatten(+List1, -List2) is a predefined predicate

my_flatten(X,[X]) :- + is_list(X).
my_flatten([],[]).
my_flatten([X|Xs],Zs) :- my_flatten(X,Y), my_flatten(Xs,Ys), append(Y,Ys,Zs).

1.08 (): Eliminate consecutive duplicates of list elements

Predicate: compress(L1,L2) – the list L2 is obtained from the list L1 by compressing repeated occurrences of elements into a single copy of the element.
Arguments: (list,list) (+,?)

compress([],[]).
compress([X],[X]).
compress([X,X|Xs],Zs) :- compress([X|Xs],Zs).
compress([X,Y|Ys],[X|Zs]) :- X \= Y, compress([Y|Ys],Zs).

1.09 (**): Pack consecutive duplicates of list elements into sublists

Predicate: pack(L1,L2) – the list L2 is obtained from the list L1 by packing repeated occurrences of elements into separate sublists.
Arguments: (list,list) (+,?)

pack([],[]).
pack([X|Xs],[Z|Zs]) :- transfer(X,Xs,Ys,Z), pack(Ys,Zs).

% transfer(X,Xs,Ys,Z) Ys is the list that remains from the list Xs %    when all leading copies of X are removed and transferred to Z

transfer(X,[],[],[X]). transfer(X,[Y|Ys],[Y|Ys],[X]) :- X \= Y. transfer(X,[X|Xs],Ys,[X|Zs]) :- transfer(X,Xs,Ys,Zs).

1.14 (*): Duplicate the elements of a list

Predicate: dupli(L1,L2) – L2 is obtained from L1 by duplicating all elements.
Arguments: (list,list) (?,?)

dupli([],[]).
dupli([X|Xs],[X,X|Ys]) :- dupli(Xs,Ys).

1.15 (**): Duplicate the elements of a list a given number of times

Predicate: dupli(L1,N,L2) – L2 is obtained from L1 by duplicating all elements N times.
Arguments: (list,integer,list) (?,+,?)

dupli(L1,N,L2) :- dupli(L1,N,L2,N).

% dupli(L1,N,L2,K) :- L2 is obtained from L1 by duplicating its leading %    element K times, all other elements N times. %    (list,integer,list,integer) (?,+,?,+)

dupli([],,[],). dupli([_|Xs],N,Ys,0) :- dupli(Xs,N,Ys,N). dupli([X|Xs],N,[X|Ys],K) :- K > 0, K1 is K - 1, dupli([X|Xs],N,Ys,K1).

1.16 (**): Drop every N’th element from a list

Predicate: drop(L1,N,L2) – L2 is obtained from L1 by dropping every N’th element.
Arguments: (list,integer,list) (?,+,?)

drop(L1,N,L2) :- drop(L1,N,L2,N).

% drop(L1,N,L2,K) :- L2 is obtained from L1 by first copying K-1 elements %    and then dropping an element and, from then on, dropping every %    N'th element. %    (list,integer,list,integer) (?,+,?,+)

drop([],,[],). drop([|Xs],N,Ys,1) :- drop(Xs,N,Ys,N). drop([X|Xs],N,[X|Ys],K) :- K > 1, K1 is K - 1, drop(Xs,N,Ys,K1).

1.18 (**): Extract a slice from a list

Predicate: slice(L1,I,K,L2) – L2 is the list of the elements of L1 between index I and index K (both included).
Arguments: (list,integer,integer,list) (?,+,+,?)

slice([X|],1,1,[X]).
slice([X|Xs],1,K,[X|Ys]) :- K > 1, 
   K1 is K - 1, slice(Xs,1,K1,Ys).
slice([_|Xs],I,K,Ys) :- I > 1, 
   I1 is I - 1, K1 is K - 1, slice(Xs,I1,K1,Ys).

1.19 (**): Rotate a list N places to the left

Predicate: rotate(L1,N,L2) – the list L2 is obtained from the list L1 by rotating the elements of L1 N places to the left.
Examples:
rotate([a,b,c,d,e,f,g,h],3,[d,e,f,g,h,a,b,c])
rotate([a,b,c,d,e,f,g,h],-2,[g,h,a,b,c,d,e,f])
Arguments: (list,integer,list) (+,+,?)

:- ensure_loaded(p1_17).

rotate([],_,[]) :- !. rotate(L1,N,L2) :-    length(L1,NL1), N1 is N mod NL1, split(L1,N1,S1,S2), append(S2,S1,L2).

1.20 (): Remove the K’th element from a list

The first element in the list is number 1.
Predicate: remove_at(X,L,K,R) – X is the K’th element of the list L; R is the list that remains when the K’th element is removed from L.
Arguments: (element,list,integer,list) (?,?,+,?)

remove_at(X,[X|Xs],1,Xs).
remove_at(X,[Y|Xs],K,[Y|Ys]) :- K > 1, 
   K1 is K - 1, remove_at(X,Xs,K1,Ys).

1.21 (): Insert an element at a given position into a list

The first element in the list is number 1.
Predicate: insert_at(X,L,K,R) – X is inserted into the list L such that it occupies position K. The result is the list R.
Arguments: (element,list,integer,list) (?,?,+,?)

:- ensure_loaded(p20).

insert_at(X,L,K,R) :- remove_at(X,R,K,L).

1.22 (*): Create a list containing all integers within a given range

Predicate: range(I,K,L)I <= K, and L is the list containing all consecutive integers from I to K.
Arguments: (integer,integer,list) (+,+,?)

range(I,I,[I]).
range(I,K,[I|L]) :- I < K, I1 is I + 1, range(I1,K,L).

1.23 (**): Extract a given number of randomly selected elements from a list

Predicate: rnd_select(L,N,R) – the list R contains N randomly selected items taken from the list L.
Arguments: (list,integer,list) (+,+,-)

:- ensure_loaded(p1_20).

rndselect(,0,[]). rnd_select(Xs,N,[X|Zs]) :- N > 0,     length(Xs,L),     I is random(L) + 1,     remove_at(X,Xs,I,Ys),     N1 is N - 1,     rnd_select(Ys,N1,Zs).