prolog implement custom flatten - prolog

Hello I have a list of list in prolog and I want to flatten them. I've made a preidacate that flatten lists as I wanted but I have this case:
[[2,2,3],[3,2]] to be flattened like this: [2,2,3,0,3,2]
i.e., I want to add a 0 to the new list if the last element of the previous list is the same as the first element of the next list. Can you help me?
here is my work so far:
myflat([],[]) :- !.
myflat([H|T],Z) :- myflat(H,K), myflat(T,L), append(K,L,Z),!.
myflat(H,[H]) :- not(H = [K]).
but I cannot think how to check the equality of elements stated above

Not perfect but works:
myflat([[A,B|List]|ListOfLists], [A|Output]) :-
myflat([[B|List]|ListOfLists], Output).
myflat([[A],[A|List]|ListOfLists], [A,0|Output]) :-
myflat([[A|List]|ListOfLists], Output).
myflat([[A],[B|List]|ListOfLists], [A|Output]) :-
A =\= B,
myflat([[B|List]|ListOfLists], Output).
myflat([[A]], [A]).
Sample input/output:
?- myflat([[1,2,1],[1,2],[2,1]], X).
X = [1, 2, 1, 0, 1, 2, 0, 2, 1] .
?- myflat([[2,2,3],[3,2]],X).
X = [2, 2, 3, 0, 3, 2] ;
false.

Related

Prolog: obtain a list with two sublists, containing the odd position elements and the even position elements. How to Improve this code

I would like to ask, if anyone knows how to improve (if it's not optimal) this code.
The idea, is that you have a list of elements, and I want to return a list, with two sublists inside it, the first sublist should contain the elements that are contained in the odd positions of the list, and the second sublist should contain, the elements that are contained in the even positions of the list.
Some examples:
?-evenAndOdd([1,2,3,4,5],[[1,3,5],[2,4]])
True.
?-evenAndOdd([a,b,c,d,e],[[a,c,e],[b,d]]).
True.
The code I have implemented is the next one:
evenAndOdd([],[]).
evenAndOdd([H|R],NL):-
evenAndOddRec([H|R], [[],[]],1,NL).
evenAndOddRec([], [LOdd,LEven],_,[LOdd,LEven]).
evenAndOddRec([H|R],[LOdd,LEven],Pos,NL):-
\+ even(Pos),
!,
NPos is Pos +1,
append(LOdd,[H],NLOdd),
evenAndOddRec(R,[NLOdd,LEven],NPos,NL).
evenAndOddRec([H|R],[LOdd,LEven],Pos,NL):-
NPos is Pos + 1,
append(LEven, [H], NLEven),
evenAndOddRec(R,[LOdd, NLEven],NPos,NL).
even(N):-
N mod 2 =:=0.
One symptom that the code is not optimal is that it will run off into the woods if you ask for an additional solution in the -,+,+ instantiation pattern:
?- evenAndOdd(X, [[1,3,5], [2,4,6]]).
X = [1, 2, 3, 4, 5, 6] ;
<time passes>
This kind of thing is a frequent occurrence when manually trying to match up lists with indexes in Prolog.
Stylistically, I would rather not give back a list containing exactly two lists when I could just have three arguments instead of two; this is, after all, a relationship between three lists, the combined list and the even and odd items.
Additionally, just eyeballing it, I'm not sure why any arithmetic or any cuts are needed here. This is how I would implement it:
evenAndOdd([], [], []).
evenAndOdd([O], [O], []).
evenAndOdd([O,E|Rest], [O|ORest], [E|ERest]) :- evenAndOdd(Rest, ORest, ERest).
This works with many instantiations:
?- evenAndOdd([1,2,3,4,5,6], O, E).
O = [1, 3, 5],
E = [2, 4, 6].
?- evenAndOdd([1,2,3,4,5], O, E).
O = [1, 3, 5],
E = [2, 4] ;
false.
?- evenAndOdd(X, [1,3,5], [2,4]).
X = [1, 2, 3, 4, 5] ;
false.
?- evenAndOdd(X, [1,3,5], [2,4,6]).
X = [1, 2, 3, 4, 5, 6].
?- evenAndOdd(X, [1,3,5], [2,4,6,8]).
false.
?- evenAndOdd([1,2,3,4,5,6], X, [2,4,6,8]).
false.
?- evenAndOdd([1,2,3,4,5,6], X, [2,4,6]).
X = [1, 3, 5].
You can implicitly determine even and odd values upon recursion, by taking two elements at a time (and taking into account when the has an odd number of elements):
evenAndOdd(L, [LOdd, LEven]):-
evenAndOdd(L, LOdd, LEven).
evenAndOdd([], [], []).
evenAndOdd([Odd], [Odd], []).
evenAndOdd([Odd,Even|Tail], [Odd|LOdd], [Even|LEven]):-
evenAndOdd(Tail, LOdd, LEven).

Prolog - Why does my definition for append_list not return the combined list?

% appends an element to the beginning of a list.
append_element(X, T, [X|T]).
% append a list to another list to create a combined list,
% by breaking the first list apart, and using append_element.
append_list([], L, L).
append_list([H|T], L, NewList) :-
append_element(H, L, NL),
append_list(T, NL, NL).
When I try to run append_list,
?- append_list([1,2], [3, 4, 5], NL).
I get back false. Instead of
NL = [2, 1, 3, 4, 5].
Why?

Generating subsets using length/2 and ord_subset/2

I am a beginner in prolog. I tried this in swipl interpreter:
?- length(Lists, 3), ord_subset(Lists, [1, 2, 3, 4]).
false.
expecting to get all length-3 lists that are subsets of [1, 2, 3, 4] like [1, 2, 3] or [1, 2, 4]. Why do i get false?
Notice: both length and ord_subset are builtin functions (or whatever they are called) in SWI-Prolog.
You don't get a solution because the ord_subset/2 predicate only checks if a list is a subset of another list; it does not generate subsets.
Here is one simplistic way to define a predicate that does what you seem to be after:
subset_set([], _).
subset_set([X|Xs], S) :-
append(_, [X|S1], S),
subset_set(Xs, S1).
This assumes that these are "ordsets", that is, sorted lists without duplicates.
You will notice that the subset happens to be also a subsequence. We could have written instead:
subset_set(Sub, Set) :-
% precondition( ground(Set) ),
% precondition( is_list(Set) ),
% precondition( sort(Set, Set) ),
subseq_list(Sub, Set).
subseq_list([], []).
subseq_list([H|T], L) :-
append(_, [H|L1], L),
subseq_list(T, L1).
With either definition, you get:
?- length(Sub, 3), subset_set(Sub, [1,2,3,4]).
Sub = [1, 2, 3] ;
Sub = [1, 2, 4] ;
Sub = [1, 3, 4] ;
Sub = [2, 3, 4] ;
false.
You can even switch the order of the two subgoals in the example query, but this is probably the better way to write it.
However, the second argument must be ground; if it is not:
?- subset_set([A,B], [a,B]), B = a.
A = B, B = a ; Not a real set, is it?
false.

Create a newlist with elements of the sublists by my List

I have this list :
C = [[1,0],[2,3],[1,2],[1,3]]
I'll like find if the number 1 included in a sublist inside my list in position [1,_ ] and i like to save to a list Newlist the number of X ..... [1,X].
I will give an example... i have the list C and i am searching for sublist which first element it's 1 and give me the Newlist.
The Newlist must be : Newlist=[0,2,3]
It had the second element of the sublists who has the number 1 at the first element.
If you use SWI-Prolog with module lambda.pl, (you can find it at http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl) you can write
:- use_module(library(lambda)).
my_filter(V, L, R) :-
foldl(V+\X^Y^Z^(X = [V,W]
-> append(Y, [W], Z)
; Z = Y),
L, [], R).
nth0/3 allows to access list' elements by index:
?- C = [[1,0],[2,3],[1,2],[1,3]], findall(P, nth0(P, C, [1,_]), NewList).
C = [[1, 0], [2, 3], [1, 2], [1, 3]],
NewList = [0, 2, 3].
edit I'm sorry I didn't read the question right. nth0 is misleading. Could be instead
findall(E, member([1,E], C), NewList)
You need a "filter". This is what it could look like:
filter_1_at_pos_1([], []). % The new list is empty when the input list is empty
filter_1_at_pos_1([[1,X]|Sublist], [X|Xs]) :- % The first element is 1 so the
% second element belongs to the
% new list
!, filter_1_at_pos_1(Sublist, Xs). % filter the remainder of the list
filter_1_at_pos_1([[N,_]|Sublist], Xs) :-
N \== 1, % The first element is not 1, ignore the second element
!, filter_1_at_pos_1(Sublist, Xs).
As #mbratch suggested, just define the solution for one element of the input list for each possible condition, in this case 1) empty list 2) first element is 1 and 3) first element is not 1.
?- C = [[1,0],[2,3],[1,2],[1,3]], filter_1_at_pos_1(C, NewList).
C = [[1, 0], [2, 3], [1, 2], [1, 3]],
NewList = [0, 2, 3].
The cuts make the predicate deterministic. The cut in the last clause is not necessary.

Removing first occurrence in list - prolog

I need to remove only one occurrence in the list. Actually doesn't matter if it's first or last. One match needs to be removed.
I'm having trouble understanding why the following doesn't work as intended.
deleteOne(_,[],[]).
deleteOne(Term, [Term|Tail], Result) :-
deleteOne(Term, [], [Result|Tail]), !.
deleteOne(Term, [Head|Tail], [Head|TailResult]) :-
deleteOne(Term, Tail, TailResult), !.
Output
41 ?- deleteOne(5,[2,3,1,5,2,3,1],X).
X = [2, 3, 1, 5, 2, 3, 1].
It works when I replace term with an empty String or some random String.
deleteOne(Term, [Term|Tail], Result) :-
deleteOne("", Tail, Result), !.
Output
41 ?- deleteOne(5,[2,3,1,5,2,3,1],X).
X = [2, 3, 1, 2, 3, 1].
But I don't think this is the best solution for many reasons. Not for my current problem, but for example longer lists. Or if a list contains empty String - don't know if this is possible in Prolog.
Why wont the first example work? And what other solutions are there?
Your first one doesn't work because this doesn't make much sense:
deleteOne(Term, [Term|Tail], Result) :-
deleteOne(Term, [], [Result|Tail]), !.
That means the result of the next one has to have the current result as its head.
An better solution would be this:
delete_one(_, [], []).
delete_one(Term, [Term|Tail], Tail).
delete_one(Term, [Head|Tail], [Head|Result]) :-
delete_one(Term, Tail, Result).
If you want it to be determinative, add a cut on the second clause. As is, it can do this:
?- delete_one(2, [1, 2, 3, 1, 2, 3], X).
X = [1,3,1,2,3] ? ;
X = [1,2,3,1,3] ? ;
X = [1,2,3,1,2,3] ? ;
no
To delete only the first occurrence of an item X from a list L.Here I used cut operation.
delete(X,[X|T],T):-!.
delete(X,[Y|T],[Y|T1]):-delete(X,T,T1).

Resources