I'm looking for an alternative to sort/4. The built-in version is currently unavailable to me.
If it was available, the syntax I need would look like this sort(1, #>=, List, Sorted). The elements in the list look like this ([Value:x:y,z:a]:[], ...). The result has to be sorted in descending order according to the Value parameter.
An example list for testing purposes:
[ [16:x:y,z:a]:[], [64:x:y,z:a]:[], [4:x:y,z:a]:[], [1024:x:y,z:a]:[], [0:x:y,z:a]:[], [100:x:y,z:a]:[], [50:x:y,z:a]:[], [-100:x:y,z:a]:[], [0:x:y,z:a]:[] ]
Just extract the key, put it in front of your structures, call sort/2 (or msort/2, to avoid losing duplicates) then strip the key from the sorted list.
The same code (a list visit) can be used to both put the key in front and remove it. The last step will reverse the list, to get descending order.
alternative_sort(Structs, Sorted) :-
structs_keyed(Structs, Keyed),
sort(Keyed, Temp),
structs_keyed(TempR, Temp),
reverse(TempR, Sorted).
structs_keyed(Sorted, Temp) :- % assume library(yall) available
maplist([S,K]>>(S=([Value|_]:_),K=Value/S), Sorted, Temp).
to be true, since the sort key value it's the first value element, could reduce to just
alternative_sort(Structs, Sorted) :-
sort(Structs, Ascending),
reverse(Ascending, Sorted).
Related
I am a total beginner in Prolog. I have some custom types: bird, animal and fish. I want to pass a list to a function like so areSameType([owl, eagle, chicken]). and get a result if the whole list is type bird or animal or fish. For example:
areSameType([owl,giraffe,shark]). > false
areSameType([owl,eagle,chicken]). > true
areSameType([cat,mouse,giraffe]). > true
The data I have inserted is:
bird(owl).
bird(eagle).
bird(chicken).
animal(cat).
animal(mouse).
animal(giraffe).
fish(shark).
fish(magikarp).
fish(gyarados).
I have tried with this function:
isSameType(X,Y):- bird(X),bird(Y);animal(X),animal(Y);fish(X),fish(Y).
areSameType([H1,H2|T]):- isSameType(H1,H2), areSameType([H2,T]).
But the problem is I don't have a criteria to check if H2 is the last element of the list or maybe I got it all wrong with this logic.
There are two problems here with your areSameType/1 predicate:
there is no stop condition: in case the list is empty, or contains exactly one element, than all the items in the list have the same type; and
you need to recurse with [H2|T] (notice the pipe |, instead of the comma ,).
So we can fix this with:
areSameType([]).
areSameType([_]).
areSameType([H1,H2|T]):-
isSameType(H1,H2),
areSameType([H2|T]).
We can however use maplist/2 [swi-doc] here, and write this predicate without recursion (well no recursion in the areSameType/1 predicate itself), like:
areSameType([]).
areSameType([H1|T]) :-
maplist(isSameType(H1), T).
I have a list of facts that have those parameters: Name, Longitude, Latitude. I want to write a predicate that sorts the Latitude only.
Here's part of my facts.
pool(roy, -75.702744, 45.4089761).
pool(marth, -75.731638, 45.3803301).
pool(jiggy, -75.7449645, 45.40431589).
pool(yamaha, -75.7114829, 45.3993461).
I tried to do something of the following but didn't get lucky:
furthest(Lat-Long):- setof(Lat-Long, pool(_, Long, Lat), [Lat-Long|_]).
Any ideas of how I should tackle this?
does this work?
pool(roy, -75.702744, 45.4089761).
pool(marth, -75.731638, 45.3803301).
pool(jiggy, -75.7449645, 45.40431589).
pool(yamaha, -75.7114829, 45.3993461).
my_sort:-
findall(forsort(Lat,Name),pool(Name,Long,Lat),List),
msort(List,Sorted),
write(Sorted).
?- my_sort.
[forsort(45.3803301,marth),forsort(45.3993461,yamaha),forsort(45.40431589,jiggy),forsort(45.4089761,roy)]
true.
Excerpt of manual below(SWI):
msort sorts List to the standard order of terms
Standard Order of Terms:
Compound terms are first checked on their arity, then on their functor name (alphabetically) and
finally recursively on their arguments, leftmost argument first.
I'm making a list of all the breed of dog sizes in my database, e.g.
breed(beagle,medium, hunting).
breed(bassets,medium, hunting).
breed(labrador,large, guideDogs).
breed(germanShepards,large, guardDogs).
breed(boxer,unknown,unknown).
breed(dalmation,unknown,unknown).
breed(ridgeback,unknown,unknown).
so I get the sizes from the database, but want to just have the unique sizes so that I can count them later. If I use
sizes(List) :- findall(Size, breed(_,Size,_), List).
I get duplicates e.g.
[medium, medium, large, unknown, unknown, unknown]
setof/3 is meant to make the set unique, so i tried
sizes(List) :- setof(Size, breed(_,Size,_), List).
but it now only return the first entry
[medium]
Any ideas why??
In prolog I'm trying to unify every valid pairing of needs with resources
needs([ece2090,1,m,13,16]).
needs([ece3520,1,tu,11,14]).
needs([ece4420,1,w,13,16]).
resources([joel, [ece2090,ece2010,ece3520,ece4420],[[m,13,16]]]).
resources([sam, [ece2010,ece4420],[]]).
resources([pete, [ece3520],[[w,13,16]]]).
using this formula
make_bid([Class,Sect,Day,Ts,Te],[Name,Cap,Unavail],[Class,Sect,Day,Ts,Te,Name,_]) :-
no_conflict_all_unavailable(Day,Ts,Te,Unavail),
course_capable(Class,Cap),
writef('%w %w %w\n',[Class,Sect,Name]),
fail.
and running this test.
test(Listing) :- needs(N), resources(R), make_bid(N,R,Listing).
The point of this part of the program is to pair every class with a teacher that both has the qualifications to teach the class and is not unavailable during that time. It's supposed to give a list.
?- test(Listing).
ece3520 1 joel
ece3520 1 pete
ece4420 1 joel
ece4420 1 sam
false.
When run, the above is generated. This is correct, but it's in a format that's useless to me, since I need it to be a variable of its own to do further computations. Then the solution is to use bagof or findall, right?
So I remove the fail clause from the main part of the program and then change the test to this
test(Bag) :- needs(N), resources(R), bagof(Listing,make_bid(N,R,Listing),Bag).
but it generates this
ece3520 1 joel
Bag = [[ece3520, 1, tu, 11, 14, joel, _G4310]]
If you look closely you'll see that there's no period at the end as well as a lack of a true/false statement. This would lead one to believe it is infinitely looping. This isn't the case however, as the Bag matrix is fully formed and I can simply type "." to end the program (instead of, you know, aborting it).
It only generates the first valid solution. Why is this happening?
You've structured your test predicate so that bagof/3 is called for every instance combination of needs(N) and resources(R) and so it collects each result of make_bid in it's own bagof/3 result:
ece3520 1 joel
Bag = [[ece3520, 1, tu, 11, 14, joel, _G4310]]
The first line is the write that is in make_bid predicate. The second line is the Bag result for the single query to make_bid for one pair of needs/resources. The last argument in the list, _G4310, occurs because your predicate uses _ and it's anonymous (never used/instantiated).
Your current make_bid is designed to write the results in a loop rather than instantiate them in multiple backtracks. So that could be changed to:
make_bid([Class, Sect, Day, Ts, Te], [Name, Cap, Unavail], [Class, Sect, Day, Ts, Te, Name, _]) :-
no_conflict_all_unavailable(Day, Ts, Te, Unavail),
course_capable(Class, Cap).
(NOTE: I'm not sure why you have _ at the end of the 3rd list argument. What does it represent?)
If you want to collect the whole result in one list, then you canb use findall/3:
findall([Class, Sect, Name], (needs(N), resources(R), make_bid(N, R, [Class, Sect, _, _, _, Name, _]), Listings).
This will collect a list of elements that look like, [Class, Sect, Name]. You could use bagof/3 here, but you'd need an existential quantifier for the variables in the make_bid/3 call that you don't want to bind.
If you wanted the entire Listing list, then:
findall(L, (needs(N), resources(R), make_bid(N, R, L)), Listings).
But each element of Listings will be a list whose last element is an anonymous variable, since that's how make_bid/3 is structured.
I'm having a bit of a problem (encountered during a Project Euler problem) in that I have a list of lists of tuples e.g.
[...
[(-119, 359), (668, -609), (-358, -494)],
[(440, 929), (968, 214), (760, -857)],
[(-700, 785), (838, 29), (-216, 411)],
[(-770, -458), (-325, -53), (-505, 633)],
...]
What I want to do is sort them by the tuple with the smallest first value, but if they are equal to then compare the second values and order by the smallest of these. I've been looking about and can't seem to find a way to do this. The only thing I have found is the old python 2.x version of sorted where it is given a cmp argument.
Any help would be much appreciated,
Regards,
Ybrad
Edit:
I just realised the above is worded slightly incorrectly. What I want to do is sort the tuples within each sub-list, not the list of lists as a whole.
You can very easily do that as:
a = [sorted(i) for i in a]
>>> print a
[[(-358, -494), (-119, 359), (668, -609)],
[(440, 929), (760, -857), (968, 214)],
[(-700, 785), (-216, 411), (838, 29)],
[(-770, -458), (-505, 633), (-325, -53)]]
For your second request, you can do it as:
a = [sorted(i, key=lambda i: (i[0], -i[1])) for i in a]