How do I count the number of elements in a list? - list

I need to write a small Prolog program to count the number of occurrence of each element in a list.
numberOfRepetition(input, result)
For example:
numberOfRepetition([a,b,a,d,c,a,b], X)
can be satisfied with X=[a/3,b/2,d/1,c/1] because a occurs three times, b occurs 2 times and c and d one time.

I don't want to give you the answer, so I gonna help you with it:
% Find the occurrences of given element in list
%
% occurrences([a,b,c,a],a,X).
% -> X = 2.
occurrences([],_,0).
occurrences([X|Y],X,N):- occurrences(Y,X,W),N is W + 1.
occurrences([X|Y],Z,N):- occurrences(Y,Z,N),X\=Z.
Depending on your effort and feedback, I can help you to get your answer.

Check out my answer to the related question "How to count number of element occurrences in a list in Prolog"!
In that answer I present the predicate list_counts/2, which should fot your needs.
Sample use:
:- list_counts([a,b,a,d,c,a,b],Ys).
Ys = [a-3, b-2, d-1, c-1].
Note that that this predicate uses a slightly different representation for key-value pairs expressing multiplicity: principal functor (-)/2 instead of (/)/2.
If possible, switch to the representation using (-)/2 for better interoperability with standard library predicates (like keysort/2).

If you wish to find element with max occurrences:
occurrences([],_,0).
occurrences([X|Y],X,N):- occurrences(Y,X,W),N is W + 1.
occurrences([X|Y],Z,N):- occurrences(Y,Z,N),X\=Z.
**make_list(Max):-
findall((Num,Elem),occurrences([d,d,d,a,a,b,c,d,e],Elem,Num),L),
sort(L,Sorted),
last(Sorted,(_,Max)).**

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.

How to select element from tuple by index in list?

I want to select elements from a list, [[1,2],[3,4],[5,6]] once the first, than the second, than again the first and so on.
I figured that i could use zip to add a counter in front of the pairs and use modulo to select the part, and now my list looks like this:
let a = [(0,[1,2]),(1,[3,4]),(2,[5,6]),(3,[7,8]),(4,[9,10])]
but how can I now select the elements?
the pseudocode would be
for each tuple in list:
first part of tuple is the selector, second part is the pair
if selector mod 2 : choose pair[0] else choose pair[1]
the output for the list a should be: 1,4,5,7,9
Perhaps:
> zipWith (!!) [[1,2],[3,4],[5,6],[7,8],[9,10]] (cycle [0,1])
[1,4,5,8,9]
If you know you're working with lists of length two inside, you should probably be using pairs instead.
> zipWith ($) (cycle [fst, snd]) [(1,2),(3,4),(5,6),(7,8),(9,10)]
[1,4,5,8,9]
I like #DanielWagner answer a lot. The first is so simple and effective. His second is a just a little harder to understand but simple, too. When theories are simple, it increases their veracity. Here is my sorry solution but it does use your structure. (Association lists are tuples. It was suggested you use tuples but for this, what you have and probably need is okay.)
a = [(0,[1,2]),(1,[3,4]),(2,[5,6]),(3,[7,8]),(4,[9,10])]
[if even i then x else y | (i,(x:y:z)) <- a]
[1,4,5,8,9]

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 Clear List of positive elements without using cuts

I want to clear a list without cutting. I tried:
filter([],[]).
filter([H|T],[H|S]) :-
H<0,
filter(T,S).
filter([H|T],S) :-
H>=0,
filter(T,S).
But it doesn't work.
Here is what happened when I tried:
?- filter([1,0,-6,7,-1],L).
L = [-6,-1]; %false
no
L=[0,-6,-1] %true
Here's one way to do it:
filter([ ],[ ]).
filter([H|T],X) :-
( H > 0 -> X = Y ; X = [H|Y] ),
filter(T,Y).
Because the if-then-else construct in Prolog is sometimes described as having a "hidden cut", meaning that Prolog will not retry (backtrack) the logical outcome in the "if" portion of this construct (it commits to the first and only outcome), it's conceivable that your course instructor might object to this solution (even though no actual cut is used).
But your solution is partially wrong. You lump the zero elements with the positive ones, where your Question's wording suggests only the positive entries need to be "cleared" from the list.

Prolog list adding

--the question has been edited--
Using this data, I need to create a list:
team(milan,1).
team(napoli,2).
team(lazio,3).
team(roma,4).
team(inter,4).
team(juventus,5).
So, given a query like:
check([milan,lazio,roma,inter]).
make a new list with their respective team number.
X=[1,3,4,4]
What I'm trying to do is creating a list, adding elements one at a time.
check([H|T]) :-
team(H,R),
append([R],_, X),
check(T).
Could someone help me complete this?
You need to find all the team numbers for which the name of the team is a member of the list of team names that you are interested in:
?- findall(Number, (
team(Name, Number),
member(Name, [milan, lazio, roma, inter])), Numbers).
Numbers = [1, 3, 4, 4].
To return the numbers in a given order, just apply member/2 before team/2, in this case member/2 generates names (in the given order), and team/2 maps them to numbers:
?- findall(Number, (
member(Name, [lazio, milan, inter]),
team(Name, Number)), Numbers).
Numbers = [3, 1, 4].
A lot of time since I used Prolog but an answer -more or less- would look like:
check([]) :- true.
check([X]) :- team(X,_).
check([X,Y]) :- team(X,N), team(Y,M), N < M.
check([X,Y|T]) :- check(X,Y), check([Y|T]).
See this question for a very similar problem.
From what you say you might be better off making a list and then sorting it. That way you'd know the list is in order. Of course it's tricky in that you are sorting on the team ranks, not the alphabetic order of their names.
But the question you asked is how to check the list is in sorted order, so let's do it.
check([ ]). % just in case an empty list is supplied
check([_]). % singleton lists are also in sort order
check([H1,H2|T]) :-
team(H1,R1),
team(H2,R2),
R1 <= R2,
check([H2|T]).
Note that the recursion reduces lists with at least two items by one, so the usual termination case will be getting down to a list of length one. That's the only tricky part of this check.
Added in response to comment/question edit:
Sure, it's good to learn a variety of simple "design patterns" when you are getting going with Prolog. In this case we want to "apply" a function to each item of a list and build a new list that contains the images.
mapTeamRank([ ],[ ]). % image of empty list is empty
mapTeamRank([H|T],[R|S]) :-
team(H,R),
mapTeamRank(T,S).
So now you have a predicate that will turn a list of teams LT into the corresponding list of ranks LR, and you can "check" this for sorted order by calling msort(LR,LR):
check(LT) :-
mapTeamRank(LT,LR),
msort(LR,LR).