Prolog list consecutive pairs - list

If I have a list [1,2,3,4,5], how can I get consecutive pairs and perform an operation on them? For example, I want to get (1,2) and perform doSomething on them. In the next iteration, I want to get (2,3), and so on. This is what I have so far:
listpairs([H1,H2|T]):-doSomething(H1,H2), listpairs([H2,H3|T]).
I can do the first iteration but I'm stuck when comparing H2 and H3.

Firstly, if you've got [1,2,3,4,5], then [H1,H2|T] sets H1 = 1, H2 = 2, T = [3,4,5]. H1 and H2 are the two numbers you want to work on. [H2|T] = [2,3,4,5] makes the list that you can proceed to calculate on. (It starts with 2,3 after all, so recursing on it will give you the two next numbers you want.)
So your recursive case should be:
listpairs([H1,H2|T]) :- doSomething(H1,H2), listpairs([H2|T]).
I.e.: Take H1 and H2 out, do something with them, then put H2 back and recurse.
Secondly, you need a base case for only having one element left:
listpairs([H]).
If you omit this, you'll never reach a base case if the list has e.g. 5 elements, since we always put 1 back. (I.e., the list you recurse on will never be empty.)

instead of an explicit 'loop', you could use this idiomatic approach:
forall(append(_,[X,Y|_],List), doSomething(X,Y)).

Related

Counting how many elements in a list of lists satisfy a predicate

Given a list of lists of integers, e.g. [[3,10],[3,10,2],[5],[5,2],[5,3],[5,3,2],[5,3,10]], I want to go over each sublist and count how many of them sum to 15. In this case that would be 1, for the sublist [3,10,2].
I am aware of the predicate aggregate_all/3, but I'm having trouble writing a predicate to check each element of the list, what I have now is something like
fifteens([X|Xs]) :-
sum_list(X, 15),
fifteens(Xs).
and within another predicate I have:
aggregate_all(count, fifteens(Combinations), Value).
where Combinations is the list of lists of integers in question.
I know my fifteens predicate is flawed since it's saying that all elements of the nested list must sum to 15, but to fix this how do I take out each element of Combinations and check those individually? Do I even need to? Thanks.
First of all your fifteens/2 predicate has no because for empty list and thus it will always fails because due to the recursion eventually fifteens([]) will be called and fail.
Also you need to change completely the definition of fifteens, currently even if you add base case, it says check ALL elements-sublists to see if they sum to 15. That's Ok but I don't see how you could use it with aggregate.
To use aggregate/3 you need to express with fifteens/2, something like: for every part of my combinations list check separately each sublist i.e each member:
ifteens(L) :-
member(X,L),
sum_list(X, 15).
Now trying:
?- aggregate_all(count, ifteens([[3,10],[3,10,2],[5],[5,2],[5,3],[5,3,2],[5,3,10]]), Value).
Value = 1.
This is a job for ... foldl/4. Functional programming idioms in logic programming languages? Yes, we can!
First, summing the summable values of a list:
sum_them(List,Sum) :-
foldl(sum_goal,List,0,Sum).
sum_goal(Element,FromLeft,ToRight) :-
must_be(number,Element),
must_be(number,FromLeft),
ToRight is Element+FromLeft.
Then, counting the ones that sum to 15:
count_them(List,Count) :-
foldl(count_goal,List,0,Count).
count_goal(Element,FromLeft,ToRight) :-
must_be(list(number),Element),
must_be(number,FromLeft),
sum_them(Element,15) -> succ(FromLeft,ToRight) ; FromLeft = ToRight.
Does it work? Let's write some unit tests:
:- begin_tests(fifteen_with_foldl).
test("first test",true(R==1)) :-
count_them([[3,10],[3,10,2],[5],[5,2],[5,3],[5,3,2],[5,3,10]],R).
test("test on empty",true(R==0)) :-
count_them([],R).
test("test with 2 hist",true(R==2)) :-
count_them([[15],[],[1,1,1,1,1,10]],R).
:- end_tests(fifteen_with_foldl).
And so:
% PL-Unit: fifteen_with_foldl ... done
% All 3 tests passed
true.

Reverse every second list of lists in Prolog

I have a list containing lists and I want to reverse every second list in it. I tried something but if I have odd number of elements in the list the last list element is lost... So the best solution would be to put the odd lists first and the even lists second till every second list is reversed.
I can't use any libraries. I need to do it recursively or split them and append them again. The best thing I made so far was to reverse only the first even list and append the first odd and even list in a new list.
I tried to do this:
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
And this:
reverselist(List1, List2).
reverselist([H|Ts], [Odd|R]):-
not(0 is H mod 2),
append(H, [], Odd),
reverselist(Ts, R).
reverselist([H|Ts], [Even|R]):-
0 is H mod 2,
reverse(H, Even),
reverselist(Ts, R).
Sample query:
?- reverselist([[a,b,c],[d,a,b],[c,d,o],[b,c,d],[e,e,d]], List).
I want the result to be:
List = [ [a,b,c],[b,a,d],[c,d,o],[d,c,b],[e,e,d] ].
You can also write mutual recursion:
reverselist([],[]).
reverselist([H|T],[H|T1]):-reverselist2(T,T1).
reverselist2([],[]).
reverselist2([H|T],[H1|T1]):-reverse(H,H1), reverselist(T,T1).
You were pretty close with your first variant.
Instead of your
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
just tweak it as
reverselist([], []). % additional clause
reverselist([List], [List]).
reverselist([X,Y|Rest], [X,EvenList|Rest2]):-
reverse( Y, EvenList),
reverselist( Rest, Rest2).
All three clauses are mutually exclusive and together they are exhaustive, i.e. they cover every possibility.
I believe this definition to be the most immediate and close representation of your problem. In Prolog, to formulate the problem means to have the solution for it.
We need to create another predicate with one more argument to keep track of odd or even position:
reverselist(InList,OutList):- reverselist(InList,OutList, 0).
reverselist([],[],_). %base case
%case of even position
reverselist([H|T],[H|T1], 0):- reverselist(T,T1,1).
%case of odd position
reverselist([H|T],[H1|T1], 1):- reverse(H1,H), reverselist(T,T1,0).

How to write a prolog program that takes List1 and List2 as inputs, and the resulting list is the alternating elements of List1 and List2? [duplicate]

This question already has answers here:
Shuffle in prolog
(2 answers)
Closed 5 years ago.
This is my first attempt at using recursion over lists on a non-sample program so bare with my inexperience!
Expected Valid Queries:
mixElements([],[a,b,c], [a,b,c]).
mixElements([a,b],[],[a,b]).
mixElements([a,b,c],[d,e,f],[a,d,b,e,c,f]).
mixElements([a,b,c],[d,e,f,g,h],[a,d,b,e,c,f,g,h]).
Here I tried to create the base case for when the inputs lists are empty, the Result is simply returned.
/* Base cases */
mixElements([],[],Result).
The logic for my recursive statement is that the input lists must be at least 1 or more elements. Thus they must both be represented by [H|L] respectively for list 1 and 2. Then it will append H1 and H2 to Result to create the alternating pattern of list elements. Finally it will call mixElements with the remainder of the lists, L1 and L2, and the Result list that should now contain the first head elements of both lists.
/* Recursive case where both L1 and L2 are not empty */
mixElements([H1|L1],[H2|L2],Result) :- append(H1,H2,Result), mixElements(L1,L2,Result).
My resulting output is always "no".
When dealing with lists it's usually worthwhile considering DCGs since they yield easily readable code. It further aids readability to choose a descriptive name for the relation, say list_list_interlocked/3. Consider the following code:
list_list_interlocked(L1,L2,I) :-
phrase(interlocked(L1,L2),I).
interlocked([],[]) --> % if both input lists are empty
[]. % the resulting list is also empty
interlocked([],[H2|T2]) --> % if the first input list is empty
[H2], % the head of the second is in the list
interlocked([],T2). % the relation holds for the tail as well
interlocked([H1|T1],[]) --> % if the second input list is empty
[H1], % the head of the first is in the list
interlocked(T1,[]). % the relation holds for the tail as well
interlocked([H1|T1],[H2|T2]) --> % if both lists are non-empty
[H1,H2], % the heads are in the list
interlocked(T1,T2). % the relation holds for the tails as well
Your example queries yield the desired result:
?- list_list_interlocked([],[a,b,c],I).
I = [a,b,c]
?- list_list_interlocked([a,b],[],I).
I = [a,b]
?- list_list_interlocked([a,b,c],[d,e,f],I).
I = [a,d,b,e,c,f]
?- list_list_interlocked([a,b,c],[d,e,f,g,h],I).
I = [a,d,b,e,c,f,g,h]
Basically there are four cases here:
the first list is empty, the second list is empty, in that case the result should be empty:
mixElements([],[],[]).
the first list is empty, the second list is non-empty, in that case, the result is the second list:
mixElements([],[H2|T2],[H2|T2]).
the first list is non-empty, the second list is empty, in that case, the result is the first list:
mixElements([H1|T1],[],[H1|T1]).
finall both lists are non-empty, in that case the two first elements of the result are the heads of the list, followed by mixing the tails of the lists:
mixElements([H1|T1],[H2|T2],[H1,H2|TT]) :-
mixElements(T1,T2,TT).
Now we can put that all together into:
mixElements([],[],[]).
mixElements([],[H2|T2],[H2|T2]).
mixElements([H1|T1],[],[H1|T1]).
mixElements([H1|T1],[H2|T2],[H1,H2|TT]) :-
mixElements(T1,T2,TT).
Now we have created some redundant statements. For instance we can merge the first two statements into one, like:
mixElements([],L,L).
mixElements([H1|T1],[],[H1|T1]).
mixElements([H1|T1],[H2|T2],[H1,H2|TT]) :-
mixElements(T1,T2,TT).
I leave it as an exercise to further improve the predicate. You can for instance use cuts, but this can eliminate the multi-direction of the predicate, which is sometimes very useful.
You're using append/3 where it's not needed. When the pattern is formed by 2 lists of at least one element, you can get the result immediately, then recurse to handle the tails:
mixElements([H1|L1],[H2|L2],[H1,H2|Rest]) :-
!, mixElements(L1,L2,Rest).
mixElements(L1,L2,Rest) :- append(L1,L2,Rest).

Prolog List Neighbour of a Element

I am having problems with list of prolog. I want to make this:
[1,2,3,4,5]
[5,6,9,12,10]
You take a number for example 3, and you do a plus operation with the neighbours so the operation is 2+3+4 = 9. For the first and the last element you pretend there is an imaginary 1 there.
I have this now:
sum_list([A,X,B|T], [Xs|Ts]):-
add(A,X,B,Xs),
sum_list([X,B|T], Ts).
I haven't consider the first and the last element. My problem is I don't know how to get the element before and the next and then how to move on.
Note: I not allow to use meta-predicates.
Thanks.
I'm not sure how you calculated the first 5. The last 10 would be 4 + 5 + implicit 1. But following that calculation, the first element of your result should be 4 instead of 5?
Anyways, that doesn't really matter in terms of writing this code. You are actually close to your desired result. There are of course multiple ways of tackling this problem, but I think the simplest one would be to write a small 'initial' case in which you already calculate the first sum and afterwards recursively calculate all of the other sums. We can then write a case in which only 2 elements are left to calculate the last 'special' sum:
% Initial case for easily distinguishing the first sum
initial([X,Y|T],[Sum|R]) :-
Sum is X+Y+1,
others([X,Y|T],R).
% Match on 2 last elements left
others([X,Y],[Sum|[]]) :-
Sum is X+Y+1.
% Recursively keep adding neighbours
others([X,Y,Z|T],[Sum|R]) :-
Sum is X+Y+Z,
others([Y,Z|T],R).
Execution:
?- initial([1,2],Result)
Result = [4,4]
?- initial([1,2,3,4,5],Result)
Result = [4, 6, 9, 12, 10]
Note that we now don't have any cases (yet) for an empty list or a list with just one element in it. This still needs to be covered if necessary.

Merge alternate elements from two lists in Prolog

I need to write a Prolog predicate mergealt(X,Y,Z) that succeeds if the list Z is a merger of alternate elements from the lists X and Y.
The input and output will like below:
?- mergealt([1,2,3,4],[6,7,8],Z).
Z = [1, 7, 3] .
?- mergealt([1,2,3,4],[6,7,8,9],Z).
Z = [1, 7, 3, 9] .
?- mergealt([1,2,3,4],[6,7,8,9,10],Z).
Z = [1, 7, 3, 9] .
I don't really understand recursion. How can I get started on this problem?
Prolog can be considered the 'flagman' of declarative languages.
So try to describe your problem, top down:
mergealt(X, Y, Z) :-
'take first element from X and put it in Z',
'discard first element from Y',
'mergealt rest-of-X and rest-of-Y, but exchange them'.
First step can't be accomplished if there are no elements in X.
This fact highlights the recursion termination case. Originally, Prolog didn't used if then else, instead alternatives are stated as different rules:
mergealt([], _Y, []).
Here you can see that pattern matching on first argument it's the key to distinguish alternatives, and contextually, Z get bound to an empty list. Y is unused, so it's marked as anonymus place holder, just to avoid a warning.
Then this simpler case suggests that we should use pattern matching to accomplish those verbose descriptions. See if you can complete the procedure with these guidelines:
mergealt([X|Xs], Y, [X|Zs]) :-
% take first element from X and put it in Z : done in the head
% discard first element from Y : see below
% mergealt rest-of-X and rest-of-Y, but exchange them'. : make your recursive call
discard_first_element([_|Rest], Rest).
% why is this necessary? do you see where it fails if we don't specify this case?
discard_first_element([], []).
Notice that the result always starts with the first element of the first list.
This means that, if the first list is empty, you know the answer right away.
Also notice that, if it isn't empty, we already know the first item of the result, so we need to use mergealt to compute the rest. But "the rest" will have the second item of the second list as the first item of the result, and as we said above, that means that a call to mergealt to compute it would have to have that be the first item of the first list (yeah, this is the tricky part).