Prolog - split a list into lists of lists - list

The list to be split is a list of guests that attend a dinner. The dinner has three meals (appetizer, main, and dessert). The result of the type list of lists should be a list for each of the meals with the sub-lists showing the people who eat that meal together.
eg.:
Appetizer: [[Tick, Trick, Track],[Tic, Tac, Toe], [Jerry, Larry, Harry]]
Main: [[Tick, Tic, Jerry], [Trick, Tac, Larry],[Track, Toe, Harry]]
Dessert: [[Tick, Tac, Larry], [Trick, Toe, Harry], [Track, Tic, Jerry]]
The function I have to code:
make_dinner(?Starters, ?Main, ?Dessert, +List_of_Persons, +Group_size):-
Group size is the size of the groups (in the example above three)
I don't know how to approach this problem using prolog language. I can easily code this in Java, which I'm really good at. But the recursion and logic here are very confusing to me. There's no "return" argument, no "if" statement", just a bunch of commas :")
My idea was to:
find out how many groups I need (depends on group size and list length)
fill the appetizer list with the original order of the list. Count it off and split the list after every group size position to get the list of lists for an appetizer (the most intuitive way I think)
fill the first sub-list of the "main" list with the first element of the list, then the second element of the other sub-lists from the "appetizer" list. Fill the second sub-list with the second element of the first sub-list of "appetizer", then the third element of the next sub-lists in "appetizer", and so on and so forth.
If the number doesn't match (eg. list length 10 but group size 3), I will simply have one group that's smaller. No person eats twice with the same person.
Does my idea work in Prolog? Can I implement that logic?
I don't really know how to approach this task because I'm very new to Prolog. I will have the main function below, then I need a helper_function called get_number_of_groups to know how many elements go into each list. And I have one function to get the size of the list.
How do I make the starters, main, and dessert into a list of lists? I know about recursion but somehow I don't know where to go from here.
%make_rudi: main function
%return: starters, main, and dessert; each list of lists
make_rudi(Starters, Main, Dessert, List_of_Persons, Group_size):-
get_number_of_groups(List_of_Persons, Group_size, Number),
%get_number_of_groups(+List_of_Persons, +Group_size, ?Number)
%return: the number of groups I have for each meal
get_number_of_groups(List_of_Persons, Group_size, Number):-
Number is list_length(Xs, List_of_Persons)/Group_size.
%list_length(?Xs,+L)
%the length of the list
list_length(Xs,L) :-
list_length(Xs,0,L) .
list_length( \[\] , L , L ) .
list_length( \[\_|Xs\] , T , L ) :-
T1 is T+1 ,
list_length(Xs,T1,L).

Related

adding frequency elt to a list of list for each elt in python

I have a list of elements (list) wich if formatted like this:
3823,La Canebiere,LOCATION
3949,La Canebiere,LOCATION
3959,Phocaeans,LOCATION
3990,Paris,LOCATION
323,Paris,LOCATION
3222,Paris,LOCATION
Some location names (elt[1]) may appear two or more times in the list, but with a different elt[0](id number). What I'm trying to achieve is adding frequency of elt[1] in the list, adding this frequency to each elt and discarding noun (elt[1]) duplicates. For my example the new tab would be :
3823,La Canebiere,LOCATION, 2
3959,Phocaeans,LOCATION,1
3990,Paris,LOCATION,3
I tried a count method and dictionnary for counting frequency but I don't know how to create the new list that would maintain the original list (without duplicates) plus the frequency. I'm using python 3. Thank you in advance if you can help !

C++ Linked List - Print in sorted order

I've made a linked list in C++ containing car objects. A car object has a few different attributes, but, for this example we will focus upon the miles per gallon (MPG) attribute.
This attribute is an int and some cars have identical MPG.
Is there a way for me to print out these items in an increasing order of MPG without actually sorting the linked list, i.e. iterating through the entire list n-times where n = the size of the linked list, outputting a car object to the user with each iteration of the list.
I apologise in advance if my question is not in the correct format, I'm new here.
Yes there is a way to do that.
Make an array of false values equal to the size of the list.
Take a new object of type car and assign it the first value in the linked list.
Iterate over the list trying to find a car with a lower MPG. if found replace it with this one.
At the end of each iteration, print this element and mark the corresponding value in the false array as true so that you dont use it again.
Example:
CAR 1 -> 2 -> 3 -> 4 -> 5-> NULL
MPG 15 25 10 41 21
arr F F F F F
After each iteration one by one arr values will become true(ie you've printed them.)

How to read each element within a tuple from a list

I want to write a program which will read in a list of tuples, and in the tuple it will contain two elements. The first element can be an Object, and the second element will be the quantity of that Object. Just like: Mylist([{Object1,Numbers},{Object2, Numbers}]).
Then I want to read in the Numbers and print the related Object Numbers times and then store them in a list.
So if Mylist([{lol, 3},{lmao, 2}]), then I should get [lol, lol, lol, lmao, lmao] as the final result.
My thought is to first unzip those tuples (imagine if there are more than 2) into two tuples which the first one contains the Objects while the second one contains the quantity numbers.
After that read the numbers in second tuples and then print the related Object in first tuple with the exact times. But I don't know how to do this. THanks for any help!
A list comprehension can do that:
lists:flatten([lists:duplicate(N,A) || {A, N} <- L]).
If you really want printing too, use recursion:
p([]) -> [];
p([{A,N}|T]) ->
FmtString = string:join(lists:duplicate(N,"~p"), " ")++"\n",
D = lists:duplicate(N,A),
io:format(FmtString, D),
D++p(T).
This code creates a format string for io:format/2 using lists:duplicate/2 to replicate the "~p" format specifier N times, joins them with a space with string:join/2, and adds a newline. It then uses lists:duplicate/2 again to get a list of N copies of A, prints those N items using the format string, and then combines the list with the result of a recursive call to create the function result.

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 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).