Reputation: 139
I am trying to write some Prolog code to take a list such as:
[[park, joe], [park, bob], [park, kate], [school, joe], [zoo, amy], [zoo, ted]].
and organizes the list into the form:
[[park,[joe, bob, kate]], [school,[joe]], [zoo,[amy, ted]]].
It can be assumed that all matching heads of each element (park = park, zoo = zoo) are directly next to each other in the list because the code I made to create the list sorts it in alphabetical order. I can't seem to figure out how to accomplish this and seem to get errors at every turn :(. Below is the code that I have so far in the last state that it ran without errors and I will try to explain what I was thinking.
merge([],[]).
merge([First|Rest], Z) :-
merge(Rest, U),
[Meet1, Person1] = First,
( =(U, []) -> % beginning case from recursion, U is empty
Meet2 = [],
Person2 = [];
[[Meet2|Person2]|_] = U),
( =(Meet1, Meet2) -> % Case of matching heads, combine the tails
print('Match '),
append([First], U, Z);
print('No-match '), % otherwise, not matching
append([First], U, Z) ).
So what I was trying to do is use appends to add all of the changes to U and return it to the console with Z. such as,
( =(Meet1, Meet2) ->
append(Person1, Person2, Combpersons),
append([Meet1], [Combpersons], T),
append(T, U, Z);
...no match code here..).
However my code keeps ending prematurely with a false when I try to change or add appends like this in the first block of code I put here. Even a change such as turning append([First], U, Z) into append([Meet1], U, Z) makes my code end with a false and I am not understanding why. Any help/hints on creating a solution would be appreciated.
Upvotes: 3
Views: 136
Reputation: 60004
I think that learning any language it's a process where low and high level issues must be interleaved. So far, you're learning the basic syntax. But why you use such unreadable constructs ? And of course, any programming language builds upon a set of patterns, usually covered by libraries. Consider
l2p([A,B],A-B).
?- maplist(l2p,[[park, joe], [park, bob], [park, kate], [school, joe], [zoo, amy], [zoo, ted]], L),group_pairs_by_key(L,G).
L = [park-joe, park-bob, park-kate, school-joe, zoo-amy, zoo-ted],
G = [park-[joe, bob, kate], school-[joe], zoo-[amy, ted]].
Anyway, here is your code restructured:
merge([],[]).
merge([[Meet, Person]|Rest], Z) :-
merge(Rest, U),
( U = []
-> % beginning case from recursion, U is empty
Z = [[Meet, [Person]]]
; U = [[Meet, Persons] | Rest1]
-> % Case of matching heads, combine the tails
Z = [[Meet, [Person | Persons]] | Rest1]
; % otherwise, not matching
Z = [[Meet, [Person]] | U]
).
Upvotes: 1
Reputation:
If you had your initial list as a list of pairs instead, you could use library(pairs), available in SWI-Prolog.
?- group_pairs_by_key([park-joe, park-bob, park-kate, school-joe, zoo-amy, zoo-ted], G).
G = [park-[joe, bob, kate], school-[joe], zoo-[amy, ted]].
Using the library gives you more than just this "reorganization". There is also library(ugraphs), which might be better suited, depending on what you are doing.
Upvotes: 1
Reputation: 2935
Your code fails, because you are trying to extract the place and the person before checking if there are any.
No use for append
here, the reordering looks pretty complicated, but I did my best with the variable names. Furthermore you'll only need one ->
: If you hadn't found a tuple with the same first coordinate, you'll want a to start a new, it doesn't matter if there was none before.
merge([],[]).
merge([[Place,Person]|Rest], [[Place,Group]|OtherGroups]) :-
merge(Rest, U),
(U = [[Place,Others]|OtherGroups] ->
Group = [Person|Others];
[OtherGroups,Group] = [U, [Person]]).
Edit: I changed the solution for readablity reasons.
Upvotes: 0