Prolog; find list item - list

I have a list of pairs and want to find the element with the corresponding first value.
?- findconn1(9, [(9,[23,33]),(42,[21,322])], R).
So in this case I want the result to be (9,[23,23]) in R.
The code is
findconn(X, [], R).
findconn(X, [(H,T)|Y], R) :-
member(X, H),
findConn(X, Y),
append(T, T, R).
It always returns false despite that the element is present. And also is there any other way to return as I'm quite new to Prolog.

Here is a simple way using built-in member/2 predicate:
findconn1(X,L,(X,L1)):- member((X,L1),L).
Example:
?- findconn1(9,[(9,[23,33]),(42,[21,322])],R).
R = (9, [23, 33]) ;
false.
With the above solution note that if 9 exists more than once you get all solutions:
?- findconn1(9,[(9,[23,33]),(42,[21,322]),(9,[1,2])],R).
R = (9, [23, 33]) ;
R = (9, [1, 2]).

Well, you don't need member/2. Just use pattern matching with a base case and a recursion case like this:
findconn1(N,[(N,B)|_],N-B). %basecase
findconn1(N,[(_,_)|T],R):-
findconn1(N,T,R).
So when you type a query:
?- findconn1(42,[(9,[23,33]),(42,[21,322])],R).
R = 42-[21, 322]
You get result in R.

Related

prolog- break a list

The example is like this
?- runs([3,4,5,4,2,7,5,6,6,8,3], RunList).
RunList = [[3, 4, 5], [4], [2, 7], [5, 6, 6, 8], [3]]
The list need to be broken in to a number of non-decreasing sequence of consecutive numbers. My code is:
next([],0).
next([H|_],R):-
R is H.
runs1([],[]).
runs1([H|T],R):-
runs1(T,R1),
next(T,X),
H=<X,
R = [H|R1].
runs1([H|T],R):-
runs1(T,R1),
next(T,X),
H>X,
R = [[H]|R1].
I tried lots of methods, but still do not know how to write it...
Hope someone could help me.
Thanks in advance.
For a logically pure and monotone implementation look at
my answer to related question "Extracting sequences (Lists) Prolog".
I present the meta-predicate splitlistIfAdj/3 which is based on if_/3 as proposed by #false in this answer.
splitlistIfAdj/3 ensures logical soundness while remaining deterministic when possible.
The predicate passed to splitlistIfAdj/3 has to obey the same convention as (=)/3 and memberd_truth/3.
For your case we need a definition of (#>)/3:
#>(X,Y,Truth) :- X #> Y #<==> B, =(B,1,Truth).
Let's use splitlistIfAdj/3 and (#>)/3 in the example you gave:
?- splitlistIfAdj(#>,[3,4,5,4,2,7,5,6,6,8,3],Pss).
Pss = [[3,4,5],[4],[2,7],[5,6,6,8],[3]]. % succeeds deterministically
Now let's ask a more general query:
?- splitlistIfAdj(#>,[A,B],Pss).
Pss = [[A],[B]], A#>=_X, B+1#=_X ;
Pss = [[A,B]], A#>=_Y#<==>_Z, B+1#=_Y, _Z in 0..1, dif(_Z,1).
Last, let's run the query that #lurker suggested in his comment to #rrrfer's answer:
?- splitlistIfAdj(#>, Ls, [[3,4,5],[4],[2,7],[5,6,6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ;
false.
runs([], []):-!.
runs([H|T], S):-
runs(T, TS),
ins(H, TS, S).
ins(E, [], [[E]]):-!.
ins(E, [[H|T]|TL], [[E, H|T]|TL]):-
H >= E, !.
ins(E, TL, [[E]|TL]).

Removing lists-within-lists from my prolog code

I've been trying to solve this problem of mine for a while now but I'm not really sure how to go about it.
For example, let's say I have this "tree" in my database:
tree4(b(b(l(Apple),l(Banana)), b(l(Orange), l(Pear)))).
I want to be able to query the database so as to retrieve the information within each l() and present it in a list. So far I've done this:
leaves(l(X), L) :-
L = X.
leaves(b(X,Y), L) :-
leaves(X, A),
leaves(Y, B),
L = [A, B].
I then query the database and it gives me this:
?- tree4(T), leaves(T, L).
T = b(b(l(1), l(2)), b(l(3), l(4))),
L = [[1, 2], [3, 4]].
The problem with this code is it generates multiple lists nestled within my original one. Is there another way to go about this? Any help would be greatly appreciated!
As you are describing a list (in this case: of leaves), consider using a DCG:
leaves(l(L)) --> [L].
leaves(b(B1,B2)) --> leaves(B1), leaves(B2).
Example query (using atoms instead of variables in tree4/1):
?- tree4(Tree), phrase(leaves(Tree), Leaves).
Tree = b(b(l(apple), l(banana)), b(l(orange), l(pear))),
Leaves = [apple, banana, orange, pear].
You can avoid the cost of the append/3 predicate by using an accumulator to collect the leaves during the traversal of the tree:
leaves(Tree, Leaves) :-
leaves(Tree, [], Leaves).
leaves(l(Leaf), Leaves, [Leaf| Leaves]).
leaves(b(Left,Right), Leaves0, Leaves) :-
leaves(Right, Leaves0, Leaves1),
leaves(Left, Leaves1, Leaves).
Using your sample call:
?- leaves(b(b(l(1), l(2)), b(l(3), l(4))), Leaves).
Leaves = [1, 2, 3, 4].
Assuming your Prolog implementation has an append predicate, you could do this:
leaves(l(X), [X]).
leaves(b(X,Y), L) :-
leaves(X, A),
leaves(Y, B),
append(A, B, L).
So leaves will always return a flat list, even if there's just one. This also assumes your tree is strictly binary, as you have it described.
Just a reminder about flatten/2, an handy builtin:
?- leaves(b(b(l(1), l(2)), b(l(3), l(4))), L), flatten(L, F).
L = [[1, 2], [3, 4]],
F = [1, 2, 3, 4].
As you can see from documentation, its use is discouraged, and you have already received plenty of good hints that allow to avoid it.

Taking a tree and making a list

I have written a program that can take a list and change it into a tree.
build_tree([X,Y],'Tree'(X,Y)) :- !.
build_tree([X|Y],'Tree'(X,Z)) :- build_tree(Y, Z).
If I want to reverse the process and take the tree and change it back into a list, how would I do this?
Note that your tree->list conversion isn't a function since trees may correspond to multiple lists:
?- build_tree([1, 2, 3], T).
T = 'Tree'(1, 'Tree'(2, 3)).
?- build_tree([1, 'Tree'(2, 3)], T).
T = 'Tree'(1, 'Tree'(2, 3)).
If you want a predicate that can generate all lists from a tree, remove the cut from build_tree and apply it with a variable first argument. If you want a deterministic conversion, write a new predicate tree_to_list.
Just curious, how would that deterministic version play out? Assuming there was only one possible list, from the tree, for example:
('Tree'('Tree'(nil, 2, nil), 5, 'Tree'(nil, 6, nil)).
Which gives: L = [5, 2, 6]
If you remove the cut from the first rule, your code it's ready to work in 'backward' mode:
?- build_tree([1,2,3,4],T).
T = 'Tree'(1, 'Tree'(2, 'Tree'(3, 4))) ;
false.
?- build_tree(X,$T).
X = [1, 'Tree'(2, 'Tree'(3, 4))] ;
X = [1, 2, 'Tree'(3, 4)] ;
X = [1, 2, 3, 4] ;
false.
flatten(leaf, []).
flatten(node(L, E, R), Ls) :-
flatten(L, Ls1),
append(Ls1, [E], Ls2),
flatten(R, Ls3),
append(Ls2, Ls3, Ls).
if you consider tree ass node(leaf,Element,leaf) for example
flatten(node(node(leaf,2,leaf),3,node(leaf,5,leaf)),X).
gives X=[2,3,5].
and if you wanna have bst
List to Tree.
insert(E,leaf,node(leaf,E,leaf)).
insert(E,node(L,N,R),T) :-
E >= N,
T=node(L,N,R1),
insert(E,R,R1).
insert(E,node(L,N,R),T) :-
E < N,
T=node(L1,N,R),
insert(E,L,L1).
list_to_tree(List,Tree) :-
list_to_tree(List,leaf,Trea2),
Tree=Trea2.
list_to_tree([],Tree,Tree).
list_to_tree([H|T],Tree,St):-
insert(H,Tree,R),
list_to_tree(T,R,St).

Prolog permutation extracting solutions

permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
If I type permutation([1,2,3],R), the first solution is "[1,2,3]" but how to get to the second one without using ";" or "fail". I need to use the 2nd solution like "[1,3,2]" or so in order compare it to another list.
What I mean is:
permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
go_perm(L,P) :-
L = P,
write(P),nl.
go_perm(L,P) :-
permutation(P,P2), % in this case i wanna get the next solution -.-
go_perm(L,P2).
If L = P then it finishes. Permutation of the first solution for "[1,2,3]" is "[1,2,3]". But that pulls me into stackoverflow because it runs into never-endless thing.
Perhaps you understand me. Thanks!
Assuming you want to loop over the solutions to print them
One standard way to accomplish this is to fail and backtrack, as in:
print_all_permutations(X)
:- permutation(X, Y), print(Y), nl, fail ; true.
Assuming you just want to check if a given solution is correct
You are already done. Just call the function with the reference list and the list you want to test:
permutation([1, 2, 3], [2, 1, 3]).
will return true, because [2, 1, 3] is a permutation of [1, 2, 3]. If the second argument is not a permutation, the goal will evaluate to false.
This is the magic of prolog: finding a solution, or checking if a given solution is correct, are the same thing.
In between: partial solution
The same reasoning still applies:
permutation([1, 2, 3], [2, X, 3]).
will display the only possible value for X.
Or, if you want the whole list to be the result:
X = [2, X, 3], permutation([1, 2, 3], X).
You need to look at various aggregate predicates. Here, findall would work nicely. you can invoke it:
ListIn=[1,2,3], findall(Perm, permutation(ListIn, Perm), Permutations).
This will call permutation on ListIn until it fails. Each Perm returned by permutation will be collected into the Permutations variable.
permutation is a predicate that succeeds when one list is a permutation of the other. You don't actually need to enumerate them; just write permutation([1, 2, 3], [2, 1, 3]) and Prolog will tell you "true".

Prolog: How to remove every second element of a list

I need to write a program in Prolog that should remove every second element of a list. Should work this: [1,2,3,4,5,6,7] -> [1,3,5,7]
so far I have this, but it just returns "false".
r([], []).
r([H|[T1|T]], R) :- del(T1,[H[T1|T]], R), r(R).
del(X,[X|L],L).
del(X,[Y|L],[Y|L1]):- del(X,L,L1).
This is pretty much Landei's answer in specific Prolog syntax:
r([], []).
r([X], [X]).
r([X,_|Xs], [X|Ys]) :- r(Xs, Ys).
The second predicate is not required.
Alternative solution using foldl/4:
fold_step(Item, true:[Item|Tail], false:Tail).
fold_step(_Item, false:Tail, true:Tail).
odd(List, Odd) :-
foldl(fold_step, List, true:Odd, _:[]).
Usage:
?- odd([1, 2, 3, 4, 5, 6, 7], Odd).
Odd = [1, 3, 5, 7]
The idea is to go through the list, while keeping "odd/even" flag and flipping its value (false -> true, true -> false) on each element. We also gradually construct the list, by appending those elements which have "odd/even" flag equal to true, and skipping others.
This fine answer by #code_x386 utilizes difference-lists and foldl/4.
Let's use only one fold_step/3 clause and make the relation more general, like so:
fold_step(X, [X|Xs]+Ys, Ys+Xs).
list_odds_evens(List, Odds, Evens) :-
foldl(fold_step, List, Odds+Evens, []+[]).
Sample queries:
?– list_odds_evens([a,b,c,d,e,f], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e]
?– list_odds_evens([a,b,c,d,e,f,g], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e,g]
Edit
Why not use one clause less and do away with predicate fold_step/3?
lambda to the rescue!
:- use_module(library(lambda)).
list_odds_evens(List, Odds, Evens) :-
foldl(\X^([X|Xs]+Ys)^(Ys+Xs)^true, List, Odds+Evens, []+[]).
Another possibility is to use DCGs, they are usually a worthwhile consideration when describing lists:
list_oddindices(L,O) :-
phrase(oddindices(L),O). % the list O is described by oddindices//1
oddindices([]) --> % if L is empty
[]. % O is empty as well
oddindices([X]) --> % if L has just one element
[X]. % it's in O
oddindices([O,_E|OEs]) --> % if L's head consists of at least two elements
[O], % the first is in O
oddindices(OEs). % the same holds for the tail
This is certainly less elegant than the solutions using foldl/4 but the code is very easily readable, yet it solves the task described by the OP and works both ways as well:
?- list_oddindices([1,2,3,4,5,6,7],O).
O = [1, 3, 5, 7] ;
false.
?- list_oddindices(L,[1,3,5,7]).
L = [1, _G4412, 3, _G4418, 5, _G4424, 7] ;
L = [1, _G4412, 3, _G4418, 5, _G4424, 7, _G4430] ;
false.
I have no Prolog here to try it out, and I got a little bit rusty, but it should be along the lines of
r([]) :- [].
r([X]) :- [X].
r([X,Y|Z]) :- R=r(Z),[X|R].
[Edit]
Of course pad is right. My solution would work in functional languages like Haskell or Erlang:
--Haskell
r [] = []
r [x] = [x]
r (x:_:xs) = x : (r xs)
In Prolog you have to "pull" the right sides into the argument list in order to trigger unification.
I just needed a function like this and took a more "mathematical" approach:
odds(Xs, Ys) :- findall(X, (nth1(I,Xs,X), I mod 2 =:= 1), Ys).
It doesn't work both ways like some of the other fine answers here, but it's short and sweet.