remove element from list without removing all duplicates - prolog

i want remove elements from a list but if i do this:
deletelist([3,1,2,3,4], [3], [3,1,2,4])
how remove only a 3 and not get this answer:
deletelist([3,1,2,3,4], [3], [1,2,4])
Thanks!

select/3 it's an useful builtin, frequently used to generate and test, and you can use to delete an element:
?- select(3,[3,1,2,3,4],L).
L = [1, 2, 3, 4] ;
L = [3, 1, 2, 4] ;
false.
each call removes a match, then you can control the desired behaviour
edit
to delete all elements from the second list:
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
select(D, With, WithoutD),
deletelist(WithoutD, Ds, Without).
Note that this will fail if any of elements to be deleted will not be found in list. To avoid this, apply a 'if .. then .. else ..'
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
( select(D, With, WithoutD)
-> deletelist(WithoutD, Ds, Without)
; deletelist(With, Ds, Without)
).
Now deletelist/3 will not enumerate all possible deletions. It commits to the first found. To resume the initial behaviour, that give on bactracking all different deletions, a less efficient procedure is required:
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
select(D, With, WithoutD),
deletelist(WithoutD, Ds, Without).
deletelist(With, [D|Ds], Without) :-
\+ select(D, With, _),
deletelist(With, Ds, Without).

If you want to get just unique values in list - use function list_to_set/2:
list_to_set([3,1,2,3,4],X) gives X = [3, 1, 2, 4].
EDIT:
So gnu prolog doesn't have built-in predicate list_to_set. You have to write it yourself.
For this you must define set concept. What is set of list ? Set should have these attributes:
Set size must be less or equal to List size.
All members of Set must be members of List.
All members of List must be members of Set.
Set must not contain duplicated values.
Based on these assumptions you can write set_from_list predicate like this:
elem_unique(Elem, List) :-
delete(List, Elem, ListWithoutElem),
length(List, OrgLength),
length(ListWithoutElem, DelLength),
DelLength + 1 =:= OrgLength.
nth_elem_isUnique(N, List) :-
nth1(N, List, Elem),
elem_unique(Elem, List).
nth_elemOfList1_isMemberOfList2(N, List1, List2) :-
nth1(N, List1, Elem),
member(Elem, List2).
elements_from_nth_areUnique(N, List) :-
(length(List, Len),
N > Len) %stoping condition for recursion
;
(nth_elem_isUnique(N, List),
M is N + 1,
elements_from_nth_areUnique(M, List) %recursion part
).
listIsUnique(List) :-
elements_from_nth_areUnique(1, List).
elements_from_nth_inList1_areMembersOfList2(N, List1, List2) :-
(length(List1, Len),
N > Len) %stoping condition for recursion
;
(nth_elemOfList1_isMemberOfList2(N, List1, List2),
M is N + 1,
elements_from_nth_inList1_areMembersOfList2(M, List1, List2) %recursion part
).
list2containsList1(List1, List2) :-
elements_from_nth_inList1_areMembersOfList2(1, List1, List2).
set_from_list(Set, List) :-
length(Set, LenSet),
length(List, LenList),
LenSet =< LenList,
list2containsList1(List, Set),
list2containsList1(Set, List),
listIsUnique(Set),
!.
So after calling set_from_list(Set, [3,1,2,3,4]) you will get Set = [3,1,2,4].

Related

I cant understand how the function subset(X,Y) works

Can somebody to explain me this code? I try for hours to understand but i can't understand this...
subset([],[]).
subset([X|L],[X|S]) :- subset(L,S).
subset(L, [_|S]) :- subset(L,S).
Imagine that you have a list [1,4], then there are four possible solutions: [1,4], [1], [4], and [], so if you call subset(L, [1,4]), we get:
?- subset(L, [1,4]).
L = [1, 4] ;
L = [1] ;
L = [4] ;
L = [].
The Prolog predicate returns for an empty list an empty list, which is indeed the only sublist we can generate:
sublist([], []).
for a sublist with at least one element X there are each time two possibilities: include X in the result, or do not include X in the result. In both cases we recurse on the tail of the list. The tail thus contains the remaining elements, and for each of these elements, there is again a decision point whether to include these elements or not.
In pseudo-code, an evaluation tree could thus look like:
subset(L, [1,4]) :-
subset([1|L], [1|S]) :-
subset([4|L], [1|S]) :-
subset([], []). % outer L=[1,4]
subset(L, [1|S]) :-
subset([], []). % outer L=[1]
subset(L, [1|S]) :-
subset([4|L], [1|S]) :-
subset([], []). % outer L=[4]
subset(L, [1|S]) :-
subset([], []). % outer L=[]
We can re-write it (nearly) equivalently to push the unifications out of the rules' headers, to make the code's structure more visually apparent:
subset(A,B) :- B=[], A=[].
subset(A,B) :- B=[X | S],
A=[X | L],
subset(L, S).
subset(A,B) :- B=[_ | S],
A= L,
subset(L, S).
So A is a subset of B, if
B=[] and A=[], or
A contains the first element of B, etc. or
A does not contain the first element of B, etc.
That is all.

Why the end of result list is not []?

I tried to output a list only contain the unique element. But the result is not perfect.
list_concatenation([],L,L).
list_concatenation([X1|L1],L2,[X1|L3]) :-
list_concatenation(L1,L2,L3).
list_member(X, [X|_]).
list_member(X, [_|TAIL]) :- list_member(X,TAIL),!.
toset([],_).
toset([X|TAIL],SET):-
list_member(X,SET),
toset(TAIL,SET).
toset([X|TAIL],SET):-
\+ list_member(X,SET),
list_concatenation([X],SET,NEWSET),
toset(TAIL,NEWSET).
For example:
?- toset([1,1,2,3],X).
the result should be 'X = [1, 2, 3]' but now, it is 'X = [1, 2, 3|_16998]'
You actually implement the toset/2 the wrong way. You actually use list_member/2 here to add an element to the list. Indeed, if you use a free variable, you get:
?- list_member(2, L).
L = [2|_3616] ;
L = [_3614, 2|_3622].
The list_member/2 itself, is not correctly implemented as well. The cut (!) here prevents to keep yielding values. You thus should remove the cut:
list_member(X, [X|_]).
list_member(X, [_|Tail]) :-
list_member(X,Tail).
This thus can yield all possible lists where 2 is a member:
?- list_member(2, L).
L = [2|_3412] ;
L = [_3410, 2|_3418] ;
L = [_3410, _3416, 2|_3424] ;
L = [_3410, _3416, _3422, 2|_3430] ;
...
But now the problem still remains: you should not use list_member/2 here to add elements to the list, you can use an accumulator here that keeps track of the elements already yielded, and then eventually return that accumulator, like:
toset(L, S) :-
toset(L, [], S).
toset([], A, S):-
reverse(A, S).
toset([H|T], A, L) :-
( member_list(H, A)
-> toset(T, [H|A], L)
; toset(T, A, L)
).
We thus keep prepending the values to the accumulator, and in the end, we reverse/2 [swi-doc] the accumulator, and return that as a result.

Replicate list by another list's number of items

I'm trying to make this:
times([x, x], [1, 5, 9, 8], Result).
The second list is replicated by the number of elements in the first one.
The result is : [1, 5, 9, 8, 1, 5, 9, 8]
I've tried this but is not working properly:
times( [ ], _, [ ] ) :- !.
times( [ _ | List1 ], List2, Result ) :- append( [], List2, Result ),
times( List1, List2, Result ).
Thanks in advance!
Firstly, you do not need your cut in the base case. It unnecessarily prunes the solution search:
replicate([], _, []). % The empty list is the result of replicating any list by []
Then your recursive rule, replicate([_|List1], List2, Result) seems to have a reasonable format/head. But you have logic issues in the body. If you were to describe the logic, it would not make sense. In particular, you're using Result in two different places for two different meanings, and that will result in unexpected failure. The predicate just needs to be thought out logically for what it means:
Result is the replication of List2 by [_|List1] if SubResult is the replication of List2 by List1 and Result is the result of appending SubResult to List2.
Note the use of a "subresult" (SubResult) here which is distinguished from the main result (Result). It's important that these be different variables.
If you write that as Prolog, you get:
replicate([_|List1], List2, Result) :-
replicate(List1, List2, SubResult),
append(List2, SubResult, Result).
I didn't test this, but this should basically do it. You should try it and resolve any residual issues yourself as part of your Prolog learning process. I also did not consider whether there's a more effective approach to the overall problem but am just resolving your issues with your current approach.
Another would be to use maplist/2 and append/2. You can use maplist/3 to get a list of lists, then use append/2 to get your result:
replicate(List1, List2, Result) :-
length(List1, Len),
length(R1, Len),
maplist(=(List2), R1),
append(R1, Result).
With a little more thought, this can be solved using simple recursive list handling. In this case, you would recursively unify the head of the result with the head of each element in the second list, then continue this process for each element in the first list.
replicate(Rep, List, Res) :-
replicate(Rep, List, List, Res).
replicate([], _, _, []).
replicate([R|Rs], List, [X|Xs], [X|Res]) :-
replicate([R|Rs], List, Xs, Res).
replicate([R|Rs], List, [], Res) :-
replicate(Rs, List, List, Res).
We can literally substitute the second list for each element in the first, then call append/2 (SWI Prolog has one):
nreplicate( Xs, Ys, Result) :-
maplist( subst(Ys), Xs, Zs),
append( Zs, Result ).
subst(Ys, _, Ys).

Pairing up items of a list according to a predicate in Prolog

I have a list of atoms in Prolog, and a predicate allowed(X, Y) that checks whether a pair of items is allowed. How can I take the list and split it into pairs of items, each of which satisfies the predicate? Ideally the pairs would be generated randomly and then checked, but this is only desired.
It can be assumed that the list has an even number of items.
pair(L1,L2,(M1,M2)) :-
member(M1,L1),
member(M2,L2).
Will retrieve, on backtracking, each possible pair. For example:
?- pair([1,2,3],[a,b],X).
X = (1, a) ;
X = (1, b) ;
X = (2, a) ;
X = (2, b) ;
X = (3, a) ;
X = (3, b).
?-
May be used on a single list, too:
?- pair([1,2,3],[1,2,3],X)
However, your question is pointless since all allowed pairs are predefined by allowed/2. You may just retrieve all solutions to allowed/2. So, this is what you are looking for, I guess:
allowed_pair(List,(A,B)) :-
allowed(A,B),
member(A,List),
member(B,List).
For example, provided that allowed/2 was defined as:
allowed(1,b).
allowed(2,a).
Then:
?- allowed_pair([1,2,3,a,4,z],X).
X = (2, a) ;
false.
?-
Depending on your performance requirements and allowed/2 implementation, you may exchange order of allowed_pair/2 goals.
I ended up doing it as follows:
checked(_, _, _, N) :-
N > 5,
fail.
checked(List, ReturnedList, [X,Y], _) :-
random_member(X, List),
select(X, List, List1),
random_member(Y, List1),
allowed(X, Y),
select(Y, List1, ReturnedList).
checked(A, B, C, N) :-
checked(A, B, C, N+1).
pairMe([], []).
pairMe(List, Result) :-
checked(List, ReturnedList, [X,Y], 0),
pairMe(ReturnedList, A),
append([[X,Y]], A, Result).
It's not great, as it doesn't guarantee that it'll always find a result even if one exists, but it works for me at least.

Prolog programs - how to make it work?

I have these two programs and they're not working as they should. The first without_doubles_2(Xs, Ys)is supposed to show that it is true if Ys is the list of the elements appearing in Xs without duplication. The elements in Ys are in the reversed order of Xs with the first duplicate values being kept. Such as, without_doubles_2([1,2,3,4,5,6,4,4],X) prints X=[6,5,4,3,2,1] yet, it prints false.
without_doubles_2([],[]).
without_doubles_2([H|T],[H|Y]):- member(H,T),!,
delete(H,T,T1),
without_doubles_2(T1,Y).
without_doubles_2([H|T],[H|Y]):- without_doubles_2(T,Y).
reverse([],[]).
reverse([H|T],Y):- reverse(T,T1), addtoend(H,T1,Y).
addtoend(H,[],[H]).
addtoend(X,[H|T],[H|T1]):-addtoend(X,T,T1).
without_doubles_21(X,Z):- without_doubles_2(X,Y),
reverse(Y,Z).
The second one is how do I make this program use a string? It's supposed to delete the vowels from a string and print only the consonants.
deleteV([H|T],R):-member(H,[a,e,i,o,u]),deleteV(T,R),!.
deleteV([H|T],[H|R]):-deleteV(T,R),!.
deleteV([],[]).
Your call to delete always fails because you have the order of arguments wrong:
delete(+List1, #Elem, -List2)
So instead of
delete(H, T, T1)
You want
delete(T, H, T1)
Finding an error like this is simple using the trace functionality of the swi-prolog interpreter - just enter trace. to begin trace mode, enter the predicate, and see what the interpreter is doing. In this case you would have seen that the fail comes from the delete statement. The documentation related to tracing can be found here.
Also note that you can rewrite the predicate omitting the member check and thus the third clause, because delete([1,2,3],9001,[1,2,3]) evaluates to true - if the element is not in the list the result is the same as the input. So your predicate could look like this (name shortened due to lazyness):
nodubs([], []).
nodubs([H|T], [H|Y]) :- delete(T, H, T1), nodubs(T1, Y).
For your second question, you can turn a string into a list of characters (represented as ascii codes) using the string_to_list predicate.
As for the predicate deleting vovels from the string, I would implement it like this (there's probably better solutions for this problem or some built-ins you could use but my prolog is somewhat rusty):
%deleteall(+L, +Elems, -R)
%a helper predicate for deleting all items in Elems from L
deleteall(L, [], L).
deleteall(L, [H|T], R) :- delete(L, H, L1), deleteall(L1, T, R).
deleteV(S, R) :-
string_to_list(S, L), %create list L from input string
string_to_list("aeiou", A), %create a list of all vovels
deleteall(L, A, RL), %use deleteall to delete all vovels from L
string_to_list(R, RL). %turn the result back into a string
deleteV/2 could make use of library(lists):
?- subtract("carlo","aeiou",L), format('~s',[L]).
crl
L = [99, 114, 108].
while to remove duplicates we could take advantage from sort/2 and select/3:
nodup(L, N) :-
sort(L, S),
nodup(L, S, N).
nodup([], _S, []).
nodup([X|Xs], S, N) :-
( select(X, S, R) -> N = [X|Ys] ; N = Ys, R = S ),
nodup(Xs, R, Ys).
test:
?- nodup([1,2,3,4,4,4,5,2,7],L).
L = [1, 2, 3, 4, 5, 7].
edit much better, from ssBarBee
?- setof(X,member(X,[1,2,2,5,3,2]),L).
L = [1, 2, 3, 5].

Resources