Increment list items by a certain value in prolog - list

I'm trying to write a predicate that increments a list item by a certain value. I wrote this one but it's not giving me the correct result:
%--Increments every single list item by a certain Value.
incList([],[],_).
incList([X | List], [X2 | List2],Value) :-
incList(List,List2),
X2 is X + Value.
It only increments the first one. Any solutions on how to solve this without changing the structure of the predicate? Thank you.

As joel76 mentioned I have a typo on line2 of second predicate. It should be incList(List,List2,Value) not incList(List,List2).

Related

Haskell: Find two related elements in a list

I am new to Haskell/FP. I want to solve this task:
This list is given: [1721, 979, 366, 299, 675, 1456]
Find the two elements that sum to 2020 and multiply them. The solution is 1721 * 299.
I think in Haskell, the tools I can use to solve this problem are list comprehension and fold (or a combination of them). But I don't understand how I can write a list comprehension that takes into account other elements of the same list, and not just one element at the time.
This is what I came up with after several hours (ints is the list):
print [(x,y, x*y) | x <- ints, y <- ints, x+y == 2020]
It actually prints the right answer. But I think my solution is dirty:
I feed the input list twice into the list comprehension. Is this correct? It seems like overhead/duplication to me. I am sure there is a better way.
The return of the function is a list with two same entities (I assume this is because of what I described in the last bullet): [(1721,608,514579),(1721,608,514579)] - of course I could get a single element with head, but that doesn't solve the root of the problem.
The reason this will emit the same value twice is because you have two iterators over the list. This thus means that at some point x will take as value 1721 and y will take as value 299; but later in the program the opposite will be true: x will take 299; and y will take 1721.
We can easily fix that problem by using tails :: [a] -> [[a]]:
import Data.List(tails)
[(x,y, x*y) | (x:ys) <- tails ints, y <- ys, x+y == 2020]
here for each suffix of ints, we will take x as the first element, and ys as the remaining elements, and then we enumerate over ys.
But this still takes quadratic time. This kan be done on O(n log n) by sorting the list, and then use recurse where we enumerate over both ends of the list until we find a value equal to 2020. Another option is to make use of a collection like a HashSet. Then we first store the elements in the HashSet, and then for each element x in the list, we check if 2020 - x is in the HashSet. I leave these as an execise.

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.

Best way to remove the first elements from each list in a list of lists in Prolog?

I am trying to remove the first element of every list in a list of lists.
For example, to list [[1,2],[3,4]], I should return [[2],[4]].
In most situations, this code below will work fine:
remove_firstElem([],[]).
remove_firstElem([[_H|T]|Ls],[T|L]) :-
remove_firstElem(Ls,L).
But for lists like [[1],[2]], I would like it to return [] rather than [[],[]].
What I tried so far looks like:
remove_firstElem([_H|Ls],L) :-
length(_H,1),
remove_firstElem(Ls,L).
But it returns [ ],[[ ]],[[ ]],[[ ],[ ]] and I really don't know what's wrong with it.
Can anyone help me to fix it? Thanks for any help!
If I understand it correctly, you want to pop the head of the list, but in case the list contains only one element (or none at all), that list should be removed.
We can check if the sublist contains at least two elements with the pattern:
pop_lists([[_,H2|T]|TA],[[H2|T]|TB]) :-
pop_lists(TA,TB).
so here we have a pattern [_,H2|T] for the first list. The _ binds with the first element, H2 with the second element, and the remaining elements with the tail.
Lists that can not unify with that pattern are the empty list, or a list with one element. So in that case we simply ignore them:
pop_lists([[]|TA],TB) :-
pop_lists(TA,TB).
pop_lists([[_]|TA],TB) :-
pop_lists(TA,TB).
In case we reach the end of the list, of course we unify the filter with the empty list as well:
pop_list([],[]).
we better put this clause on the first line to make our predicate more multidirectional. So in full, we have the following solution:
pop_list([],[]).
pop_list([[_,H2|T]|TA],[[H2|T]|TB]) :-
pop_list(TA,TB).
pop_list([[]|TA],TB) :-
pop_list(TA,TB).
pop_list([[_]|TA],TB) :-
pop_list(TA,TB).
We can further reorder the statements, such that the amount of backtracking is less:
pop_list([],[]).
pop_list([[]|TA],TB) :-
pop_list(TA,TB).
pop_list([[_]|TA],TB) :-
pop_list(TA,TB).
pop_list([[_,H2|T]|TA],[[H2|T]|TB]) :-
pop_list(TA,TB).
Easier way:
list_tail([_|Es], Es).
maplist(list_tail, Input, Output).

Prolog: Sort a list by alternative index

I'm attempting to sort a list of colors, by a given preffered order. For example a list [r,z,z,w,g,g,r,z] sorted in this order [z,b,g,r,w], will give an end result of [z,z,z,g,g,r,r,w].
I tried using a basic bubblesort algorithme and adding a check to see which of first two terms would be 'higher' on the order list.
% take the to-sorted list, the order in which to sort the list, and the
% result.
%colourSort([r,z,z,w,g,g,r,z],[z,b,g,r,w],X). returns X = [z,z,z,g,g,r,r,w]
colourSort(List,Order,Sorted):-
swap(List,List1,Order),
!,
colourSort(List1,Order,Sorted).
colourSort(Sorted,_,Sorted).
% check if the either the first or second letter is first in the order
% list, if neither check the next letter in the order list.
check(A,_,[H|_],A):-
A == H.
check(_,B,[H|_],B):-
B == H.
check(A,B,[_|T],R):-
check(A,B,T,R).
check(_,_,[],_).
%swap incase a set of letters isn't ordered, continues otherwise.
swap([X,Y|Rest],[Y,X|Rest],Order):-
check(X,Y,Order,R),
X == R.
swap([Z|Rest],[Z|Rest1],Order) :-
swap(Rest,Rest1,Order).
When I run the code, it ends up crashing my swi-prolog, I'm assuming it's getting stuck in a loop or something, but haven't been able to figure out why or how. Any advice or tips would be appreciated.
Here's a solution to the stated problem, which does not, however, use a custom sorting algorithm. Instead, it uses the common pairs data-structure (using the (-)/2 operator to form a list of items Key-Value) and the keysort/2 for sorting. Edit: this answer has been reworked in accordance with #mat's tip in the comments, and to provide a more succinct explanation).
Solution:
item_with_rank(Ranking, Item, Rank-Item) :-
nth0(Rank, Ranking, Item).
sort_by_ranking(Ranking, ToSort, Sorted) :-
maplist(item_with_rank(Ranking), ToSort, Ranked),
keysort(Ranked, RankedSorted),
pairs_values(RankedSorted, Sorted).
Explanation:
We define a predicate item_with_rank(Ranking, Item, Rank-Item) that uses a list of arbitrarily ordered terms as a Ranking, and associates with the given Item a Rank which is equivalent to the 0-based index of the first term in Ranking that unifies with Item. We then define sort_by_ranking(Ranking, ToSort, Sorted). sort_by_ranking/3 uses maplist/3 to call item_with_rank/3, with the given Ranking, on each element of the list ToSort, obtaining a list of pairs, Ranked, assigning a rank to each item. We use keysort/2 to sort the Ranked so that they order of elements accords with the value of their "ranks" (keys) in RankedSorted. When we extract just the values from RankedSorted, we are left with the Sorted items, which is what we were after:
Example of usage:
?- sort_by_ranking([z,b,g,r,w], [r,z,z,w,g,g,r,z], S).
S = [z, z, z, g, g, r, r, w] ;
false.

Prolog - Twice List

I am practicing prolog and all and this one is killing me. Trying to do this:
twice([1,2,3],X).
the output I want is
X = [1,1,2,2,3,3].
Here's my latest attempt:
twice([HD|TL],[HD2|TL2]):-
twice(TL,[HD,HD2|TL2]).
twice([],[HD|TL]).
//New
twice([],[]).
twice([A|B],Out):- twice([A|B],[A,A|Rest],
twice(B,Rest).
Start with the base case,
twice([],
"twice of nothing is" ... nothing, right?
[]).
Now, what if there is something there?
twice([A|B],
then what? do we want the result to start from A? You bet,
[A,
what next goes there?
...
(fill it in, please). Then, there's the rest:
| Rest] ):-
so, we continue. The Rest is taken from B:
twice(B, ...).
fill this in too, please.
Let's look at a simpler task first, a predicate where every element in input is not get to the output twice, but only once (input and output are the same, basically).
onlyonce([], []).
onlyonce([Head | Tail], [Head | NewTail]) :-
onlyonce(Tail, NewTail).
The first clause is obvious.
The second clause means:
the first argument (input) is a non-empty list. Name first element of that list "Head", name the rest elements of that list "Tail"
the second argument is a non-empty list. The first element of that list is the same as in the first argument list "Head" (i.e. the first element of the input list copied once). Name the rest elements of the list "NewTail"
"NewTail" can be obtained from "Tail" (and vice versa) using "onlyonce" predicate.
If you understand how "onlyonce" works, it's very easy to change it to "twice".
Try this:
twice([], []).
twice([A|B], [A,A|Rest]) :- twice(B, Rest).