0
votes

I have some facts like:

motherboard('name', price, 'price range', score).

I need to take the best motherboard by score, so I guess I should use findall but I'm not understanding how to order by score(desc order) and take the first! Could you help me please?

EDIT - @user27815 solution:

motherboard('Gigabyte B360M Aourus Gaming 3', 86, 'low_range', 3).
motherboard('MSI B350M Mortar', 93, 'low_range', 4).
motherboard('ASUS ROG Strix B350\u002DF', 114, 'middle_range', 6).
motherboard('MSI Z370 Tomahawk', 139, 'middle_range', 7).
motherboard('Gigabyte Aorus AX370 Gaming K7', 169, 'high_range', 8).

setof(Score-Nome,motherboard(Nome, Price,Price_range, Score),Pairs), sort(1,@>,Pairs,Sorted),
        write(Pairs),
        nl,
        write(Sorted).

The result is: [3-Gigabyte B360M Aourus Gaming 3] for both Pairs and Sorted, it ends withoud dot and I can press ; to have more solutions, why is it not printing them all together? And anyway the order is the same for pairs and sorted

@PauloMoura solution- With the same data of the previous solution: setof(Score-Nome,motherboard(Nome, Price, Price_range, Score),Pairs), last(Pairs, BestMotherboard), write(BestMotherboard).

I get this:

?- start.
3-Gigabyte B360M Aourus Gaming 3
true ;
4-MSI B350M Mortar
true ;
6-ASUS ROG Strix B350-F
true ;
7-MSI Z370 Tomahawk
true ;
8-Gigabyte Aorus AX370 Gaming K7
true.
2
You need to use setof(Score-Nome,Price^Price_range^motherboard(Nome, Price,Price_range, Score),Pairs), sort(1,@>,Pairs,Sorted), write(Pairs), nl, write(Sorted). So that the Price and Price range are ignored in the setof call. - user27815
As @user27815 noted, you need to explicitly qualify the arguments in the setof/3 second argument that you want to ignore. That will give you a single solution. - Paulo Moura

2 Answers

2
votes

Using instead the standard setof/3 predicate instead of the findall/3 predicate will give you a list sorted in ascending order. You can then traverse that list to take the last element, which will be the motherboard with the best score. Something like:

...,
setof(..., ..., Motherboards),
last(Motherboards, BestMotherboard).

The last/2 predicate is a common library predicate.

1
votes

Given:

motherboard('thing1', price, 'price range', 5).
motherboard('thing2', price, 'price range', 4).
motherboard('thing3', price, 'price range', 3).
motherboard('thing4', price, 'price range', 2).
motherboard('thing5', price, 'price range', 1).

We can query:

?-setof(Score-Thing,motherboard(Thing,price,'price range',Scores),Pairs), sort(1,@>,Pairs,Sorted).
Pairs = [1-thing5, 2-thing4, 3-thing3, 4-thing2, 5-thing1],
Sorted = [5-thing1, 4-thing2, 3-thing3, 2-thing4, 1-thing5].

setof/3 sorts the answers but not in the order you want, so we need to use sort/4 if we want the whole list sorted rather than just the topscore.

Alternatively you could define an inverse predicate (make 5 into -5 etc) and include that in the setof/3 call to avoid 'sorting twice' but you would then need to reinvert the sorted list to see the original numbers, this wont work if anything has a negative score.