Related
I am trying to get the original list from List and store it to Temp. But List gets updated during recursions so Temp can't get the original data of List before recursions. Need help on how to get the original list with the sorted sub lists so I can use them in printPerMerge. Thank you!
mSort(Sorted,List) :-
length(List, N),
copy_term(List, Temp),
write('Temp '), tab(1),
format('~w ',[Temp]), nl,
FLength is //(N, 2),
SLength is N - FLength,
length(FUnsorted, FLength),
length(SUnsorted, SLength),
append(FUnsorted, SUnsorted, List),
mSort(FSorted, FUnsorted),
mSort(SSorted, SUnsorted),
combine(Sorted, FSorted, SSorted),
printPerMerge(Sorted, Temp),
write('Sorted '), tab(1),
format('~w ',[Sorted]), nl.
It looks like you are trying to implement a merge sort. With a merge sort, there's really no need to look at list length, or pre-construct lists of the desired length.
Try something like this:
merge_sort( [] , [] ) . % The empty list is ordered, is it not?
merge_sort( [X] , [X] ) . % A list of length 1 is ordered, is it not?
merge_sort( [X,Y|Zs] , Sorted ) :- % A list of length > 1 is not [necessarily] sorted, so....
partition([X,Y|Zs], Ls, Rs) , % - Split the unordered list into two lists of equal length
merge_sort(Ls,L1) , % - Recursively sort one sublist
merge_sort(Rs,R1) , % - Recursively sort the other sublist
merge(L1,R1,Sorted) % - And merge them together, in order
. % Easy!
partition( [] , [] , [] ) .
partition( [X] , [X] , [] ) .
partition( [X,Y|Zs] , [X|Xs] , [Y|Ys] ) :- partition(Zs,Xs,Ys).
merge( [] , [] , [] ) .
merge( [X|Xs] , [] , [X|Zs] ) :- merge(Xs,[],Zs) .
merge( [] , [Y|Ys] , [Y|Zs] ) :- merge([],Ys,Zs) .
merge( [X|Xs] , [Y|Ys] , [X|Zs] ) :- X #< Y, !, merge(Xs, [Y|Ys], Zs ) .
merge( [X|Xs] , [Y|Ys] , [Y|Zs] ) :- merge([X|Xs], Ys, Zs) .
How to make it?
I need something like this:
?- elsort([d,s,a,[r,t,h]],X).
X = [a, d, s, [h, r, t]].
But i get :
?- elsort([d,s,a,[r,t,h]],X).
X = [a, d, s, [r, t, h]].
My code:
elsort([],[]).
elsort([A|B],C):-
elsort(B,D),
elsortx(A,D,C).
elsortx(A,[X|B],[X|C]):-
order(X,A),
!,
elsortx(A,B,C).
elsortx(A,B,[A|B]).
order(A,A2):-
A #< A2.
thanks for helping.
I would probably make the sorting of sublists a two-phase operation. First, iterate over your source list, sorting each sublist found. When that's done, then actually sort the final list. The rationale is to avoid the repeated sorting of sublists.
Something like this:
my_sort( Unsorted , Sorted ) :- % to sort a list of lists...
sort_sublists( Unsorted, U ) , % - 1st pass: sort any sublists
merge_sort( U , Sorted ) % - 2nd pass: actually sort the results
. %
sort_sublists( [] , [] ) . % an empty list has no sublists to sort
sort_sublists( [X|Xs] , [Y|Ys] ) :- % otherwise...
list(X) , % - if the head is a list
!, % - eliminate the choice point
my_sort(X,Y) % - and sort the head (along with its sublists)
. %
sort_sublists( [X|Xs] , [X|Ys] ). % otherwise (the head is not a list)
merge_sort( [] , [] ) . % an empty list is sorted.
merge_sort( [A] , [A] ) . % list of 1 item is sorted.
merge_sort( [A,B|Cs] , Sorted ) :- % otherwise, to sort a list of 2 or more items...
partition([A,B|Cs] , L , R ) , % - partition it into two halves.
merge_sort( L , L1 ) , % - then recursively sort the left half
merge_sort( R , R1 ) , % - and recursively sort the right half
merge( L1 , R1 , Sorted ) % - then merge the two now-order halves together
. % producing the final, sorted list
partition( [] , [] , [] ) .
partition( [L] , [L] , [] ) .
partition( [L,R|Xs] , [L|Ls] , [R|Rs] ) :- partition(Xs,Ls,Rs) .
merge( [] , [] , [] ) .
merge( [L] , [] , [L] ) .
merge( [] , [R] , [R] ) .
merge( [L|Ls] , [R|Rs] , [R,L|Xs] ) :-
compare(CC,L,R) ,
swap(CC,L,R,Lo,Hi),
merge(Ls,Rs,Xs)
.
swap( < , L , R , L , R ) .
swap( > , L , R , R , L ) .
swap( = , L , R , L , R ) .
list( X ) :- var(X) , ! , fail .
list( [] ) .
list( [_|_] ) .
Note that compare/3 is a built-in predicate that compares two terms in the standard order of things and returns an atom, one of <, = , >, with each having the obvious meaning. You could roll your own if you'd like:
compare(<,X,Y) :- X #< Y .
compare(>,X,Y) :- X #> Y .
compare(=,X,Y) :- X == Y .
You would need to sort the element itself if it is a list, e.g.:
elsort([A|B],C):-
elsort(B,D),
(is_list(A)->elsort(A, SA);SA=A),
elsortx(SA,D,C).
Sample input:
?- elsort([d,s,a,[r,t,h]],X).
X = [a, d, s, [h, r, t]].
So my professor at campus asked us to solve this exercise but is kinda tough and I am trying for 2 days now. Anyway here it is:
I'm given a list for example [a,b,c,d,w,n,i,c,k,a,b,c,d,w] and on this list I have to find out if there is "suspect" sublist. The sublist is considered "suspect" if
1) the same sublist is in the beginning and at the end,
2) it contains "w",
3) its length is 5.
The list I give has a "suspect" sublist.
If there is a suspect sublist the program must return the sublist or if there is not the program must return [o,k].
Any ideas will be welcome, thanks a lot!
(sorry if i posted something wrong)
EDIT
So after some help here is the asnwer:
checkMessage1(L,SL):-
suspiciousMessage1(L,SL).
checkMessage1(L,[o,k]):-
not(suspiciousMessage1(L,SL)).
suspiciousMessage1(L,SL):-
append(SL,Last,L),
append(_,SL,Last),
length(SL,5),
member(w,SL).
Prolog is a declarative language: describe the solution in terms of constraints and let the engine do the work.
We can determine membership in a list thus:
contains( [X|Xs] , X ) :- ! .
contains( [_|Xs] , X ) :- contains(Xs,X) .
We can determine if a lists 1st element is identical to its last element using the built-in predicate append/3:
list_starts_and_ends_with_identical( [X|Xs] ) :-
append( [X|_] , [X] , [X|Xs] )
.
Or, if you'd rather roll your own:
list_starts_and_ends_with_identical( [A|Xs] ) :-
list_ends_with( Xs , A )
.
list_ends_with( [A] , A ) .
list_ends_with( [B,C|D] , A ) :-
list_ends_with( [C|D] , A )
.
And we can enumerate sublists of the desired length like so:
sublist_of_length( Xs, L , Ys ) :- % to enumerate sublists of the desired length,
integer(L) , % - validate that the length is an integer, and
L > 0 , % - validate that the length is positive, and
length(Ys,L) , % - construct a list of unbound variables of the desired length, and
sl(Ys,L) % - invoke the helper
. %
sl( [X|Xs] , L ) :- % to enumerate sublists,
append( L , _ , [X|Xs] ) % - simply get the prefix of the desired length
. %
sl( [_|Xs] , L ) :- % on backtracking,
sl( Xs , L ) % - just recurse down on the tail of the list, discarding the first element.
.
Then, all we have to do is assemble the parts:
suspect_sublist( Xs , L ) :- % the source list Xs contains a suspect sublist L, IF...
sublist_of_length( Xs , 5 , L ) , % - L is a sublist of Xs having length 5, and
contains( L , w ) , % - L contains the atom 'w', and
list_starts_and_ends_with_identical( L ) , % - the first element of L is identical to the last.
. % Easy!
This is a good example for using DCGs:
list_suspect(Xs, Ys) :-
length(Ys, 5),
phrase(( seq(Ys), ..., seq(Ys) ), Xs),
phrase((...,"w",...), Ys).
... --> [] | [_], ... .
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
And here is a version using append/3 instead:
list_suspect(Xs, Ys) :-
Ys = [_,_,_,_,_],
append(Ys,Is, Xs),
append(_, Ys, Is).
append("w", _, W), % or: "w" = [C], W = [C|_]
append(_, W, Ys).
Is it better readable? I think not.
The part with the [o,k] looks a bit unnatural to me, but it would be:
list_ret(Xs, Ys) :-
list_suspect(Xs, Ys).
list_ret(Xs, Ys) :-
\+ list_suspect(Xs,_),
Ys = "ok".
one liner, using append/2
suspect(L, S) :-
length(S, 5), append([S,_,S], L), memberchk(w, S) -> true ; S = [o,k].
edit as noted by false, the definition is buggy (lacks steadfastness ?): an amended rule
suspect(L, R) :-
length(S, 5), append([S,_,S], L), memberchk(w, S) -> S = R ; R = [o,k].
I'm really new to Prolog and I am trying to make an isIntersection that gives me the intersection of two lists and puts the answer in the third list. I cannot use any Prolog list predicates because it's for a class and that's just the rules. This is what I have and I'm having trouble debugging and seeing why this implementation is wrong. Anyone have any ideas?
/* Checks if the item is in the list */
in(Item, [Item|Rest]).
in(Item, [Not|Rest]) :- in(Item, Rest).
/* Makes the intersection list */
isIntersection([], [], []).
isIntersection([H|R], List, [H|Final]) :-
in(H, List),
isIntersection(R, List, Final),
write(H).
isIntersection([Discard|Rest], List, Final) :-
isIntersection(Rest, List, Final),
write(Discard).
Prolog is a very versatile query language, so let's use Prolog to find the problem!
?- isIntersection([a,b],[c,b],Zs).
false.
This failure is not what we expect. To better localize the problem we might a) generalize the query or b) reduce input size. I will try generalizing it first:
?- isIntersection([a,b],Ys,Zs).
loops. % ERROR: Out of global stack
Seems we have no luck, but then this query would have to produce infinitely many lists for Ys so it might be OK to loop.
I could continue that way, but why not let Prolog do the thinking for me? I will try all possible lists:
?- length(L,_),append(Xs,Ys,L), isIntersection(Xs,Ys,Zs).
L = Xs, Xs = Ys, Ys = Zs, Zs = []
; L = Xs, Xs = [_A], Ys = Zs, Zs = []
; L = Xs, Xs = [_A, _B], Ys = Zs, Zs = []
; L = Xs, Xs = [_A, _B, _C], Ys = Zs, Zs = []
; L = Xs, Xs = [_A, _B, _C, _D], Ys = Zs, Zs = []
; ... .
So for each list length (so far), there is only one solution with Ys and Zs being an empty list... Is there any solution for Ys being larger?
?- length(L,_),Ys = [_|_], append(Xs,Ys,L), isIntersection(Xs,Ys,Zs).
loops.
So lets take the minimal missing example from above with Ys having one element:
?- isIntersection([],[a],[]).
false.
With this goal, now look at your code!
But there is another problem (after fixing above):
?- isIntersection([a],[a],Xs).
Xs = [a]
; Xs = [].
The rule discards any element! But it should only discard those that are not in List. So:
isIntersection([Discard|Rest], List, Final) :-
list_without(List,Discard), % maplist(dif(Discard),List)
isIntersection(Rest, List, Final).
list_without([], _).
list_without([E|Es], F) :-
dif(E, F),
list_without(Es, F).
Finally, always keep an eye on negative examples. Many attempts here (incorrectly) succeeds for queries like isIntersection([a],[a],[]).
(Your relation in/2 might better be called element_in/2)
I'd go at it something like this, sorting and merging so as to avoid the O(n2) performance:
intersection_of( Xs , Ys , Zs ) :- % to find the intersection of two sets, we
sort(Xs,X1) , % - sort the left source list, removing duplicates to ensure that it's a set
sort(Ys,Y1) , % - sort the right source list, removing duplicates to ensure that it's a set
merge(Xs,Ys,Z1) , % - merge them to find the common members (an ordered set)
( var(Zs) -> % - if the result is unbound,
Zs = Z1 ; % - simply unify the merge result with the result set
sort(Zs,Z1) % - otherwise, sort the result and match against the merge result
) . %
The merge is simple
merge( [] , [] , [] ) .
merge( [_|_] , [] , [] ) .
merge( [] , [_|_] , [] ) .
merge( [X|Xs] , [Y|Ys] , [X|Zs] ) :- X = Y , merge( Xs , Ys , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs ) :- X #< Y , merge( Xs , [Y|Ys] , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs ) :- X #> Y , merge([X|Xs] , Ys , Zs ) .
there is only a List that can match your base case, and this simple fact inhibits the whole computation.
I've been trying to write some code that takes a list of values, and removes all values which are only in the list once, the non-duplicates:
dbltaker([], []).
dbltaker([H | X], Y):-
\+mem(H, X),
dbltaker(X, Y).
dbltaker([H | X], [H | Y]):-
mem(H, X), !,
dbltaker(X, Y).
dbltaker([H | X], [H | Y]):-
mem(H, Y),
dbltaker(X, Y).
mem(H, [H | _]).
mem(H, [_ | T]):-
mem(H, T).
The trouble I've been having is that after I move a non-duplicate to the other list, it's duplicate is no longer a duplicate so isn't moved into the list. For example, the list [1, 1, 1, 2, 2, 3] gives [1, 1, 2] as the output, as the last one and two aren't considered duplicates as they're no longer members of their tails, and I can't check to see if they're members of the new list, as it's yet to be instantiated.
Is there a way around this?
Thanks.
I think the simpler way should be to should pass around to original list, to be able to check when an element is duplicate or not.
dbltaker(L, R) :- dbltaker(L, L, R).
dbltaker([], _L, []).
dbltaker([H|T], L, [H|R]) :- at_least_2(H, L), !, dbltaker(T, L, R).
dbltaker([_|T], L, R) :- dbltaker(T, L, R).
the service predicate at_least_2(H, L) can easily be implemented...
This is how I'd do it:
First, a check for list membership:
exists_in( A , [A|_] ) :- ! .
exists_in( A , [_|B] ) :- exists_in(A,B) .
Then a conditional add. If X is not contained in Y, add X to Y giving Z:
add_if_not_exists( X , Z , Z ) :- exists(X,T) , ! .
add_if_not_exists( X , Y , [X|Y] ) .
A worker predicate that does the hard work, using an accumulator (seeded to the empty list []) to build the set of distinct elements:
dedupe( [] , Z , Z ) . % if the source list is exhausted, we're done: the accumulator is the set of distinct list members.
dedupe( [X|Xs] , Y , Z ) :- % otherwise...
add_if_not_exists(X,Y,T) , % - add X to the accumulator if it's not already there.
dedupe(Xs,T,Z) % - and recurse down.
. % Easy!
And finally, the public interface predicate that simply invokes the worker predicate:
dedupe( Xs, Ys ) :- % dedupe a list
dedupe( Xs, [] , Ys ) % by invoking the helper predicate with the accumulator seeded with the empty set.
. %
Note: the worker predicate builds the deduped list in reverse order. If order is important, reversing a list is trivial:
rev( [] , [] ) .
rev( [X|Xs] , Rs ) :- rev( Xs , [X|Rs] ) .
Just modify the public interface to do the reversal:
dedupe1( Xs, Ys ) :- % dedupe a list
dedupe( Xs, [] , T ) , % by invoking the helper predicate with the accumulator seeded to the empty set.
rev(T,Ys) % and reversing the result.
. %