« Return to Thread: How to sort list of sublists as per key/keys of sublist?
I assume that that's a table of facts, so
On 10 Jun 2009, at 7:25 pm, Levan Cheishvili wrote:
I have the following structure:
object('obj1', [id='12', color='blue']).
object('obj4', [id='13', color='red', weight=120]).
object('obj21', [id='15 a', color='yellow', weight=1000, price=23]).
object('obj21', [id='16 a', color='blue', weight=200, price=230]).
:- type eq ---> =(atom,any).
:- pred object(atom, list(eq)).
The first thing that strikes me is that the Prolog convention for
a list of key-value pairs has been a list of Key - Value terms
since about 1979, that's 30 years. There is a standard predicate
called keysort/2 for sorting such lists. So why are you using
(=)/2 for your pairs instead of (-)/2?
[It's not that (-)/2 is a specially brilliant choice, although since
it is very often used with collections of pairs that are _not_ finite
maps, it's definitely better than (=)/2. The point is just that it
is the _better-supported_ choice.]
How come you have two facts for obj21?
The second thing that strikes me is that what you really have
I have a predicate which finds all objects with particular key, e.g. objects with color='blue'.
seems to be a ternary relation,
oav(obj1, id, 12). % Object Attribute Value
oav(obj1, colour, blue).
oav(obj4, id, 13).
oav(obj4, colour, red).
oav(obj4, weight, 120).
Or possibly a collection of binary relations
id(obj1, 12).
id(obj4, 13).
colour(obj1, blue).
colour(obj4, red).
weight(obj4, 120).
All things considered, I think the binary relations are the way I'd
do it. We can recover the other views if we really have to:
oav(Obj, id, X) :- id(Obj, X).
oav(Obj, colour, X) :- colour(Obj, X).
oav(Obj, weight, X) :- weight(Obj, X).
oav(Obj, price, X) :- price(Obj, X).
object(Obj, Attrs0) :-
( id(Obj, I) -> Attrs0 = [id =I|Attrs1] ; Attrs1 = Attrs0 ),
( colour(Obj, C) -> Attrs1 = [colour=C|Attrs2] ; Attrs2 = Attrs1 ),
( weight(Obj, W) -> Attrs2 = [weight=W|Attrs3] ; Attrs3 = Attrs2 ),
( price(Obj, P) -> Attrs3 = [price =P|Attrs4] ; Attrs4 = Attrs3 ),
Attrs4 = [].
If you want to find all the objects that are blue,
setof(Obj, colour(Obj, blue), Blue_Objs)
or even
findall(Obj, colour(Obj, blue), Blue_Objs)
is a lot easier than
setof(Obj, ( object(Obj, Attrs), member(colour=blue, Attrs) ),
Blue_Objs)There are several ways to do it.
My question is:
How to write a sorting predicate which will sort objects within a resulting list by one of one or many keys(id or/and price, etc...)
One way is to exploit the fact that keysort is stable.
So sort by the least significant key first,
then the second least significant key,
...
and finally sort by the most significant key.
To sort a list by a particular key, simply take a list whose
elements are X and make a list whose elements are Key-X, and
sort that. If you want to sort in decreasing order, just
reverse the result.
If you want ascending order for everything (except possibly
numbers, which you can negate), you can simply build
one super-key containing all the others.
For example, suppose you want to find all the blue objects
and sort them by decreasing price and (within the same price
level) increasing id.
setof( key(Minus_Price,Id) - Object
, ( colour(Object, blue),
price(Object, Price), Minus_Price is -Price,
id(Object, Id)
)
, Pairs),
pairs_values(Pairs, Objects)
where pairs_values/2 is described in http://www.cs.otago.ac.nz/staffpriv/ok/pllib.htm
That draft library specification also calls for
sort/3 and msort/3. There is a file which was written
for that but never included, because there seemed to be
very little interest in a standard library for Prolog.
I've attached it. It's called msort.pl, and I've deleted
msort/2 from it because SWI Prolog already has msort/2.
With this, you would write a 3-way comparison predicate.
Using the binary relations version of your data,
you'd write
price_and_id_compare(R, Obj1, Obj2) :-
price(Obj1, Price1),
price(Obj2, Price2),
compare(R1, Price2, Price1), % note argument order!
( R1 == (=) ->
id(Obj1, Id1),
id(Obj2, Id2),
compare(R, Id1, Id2)
;/* prices differ */
R = R1
).
Then given a list of objects you could do
msort(price_and_id_compare, Objects, Sorted_Objects)
if you want to keep duplicates, or sort/3 to discard them.
Many thanks for your guidance ! I really appreciate your help.
Thanks!
« Return to Thread: How to sort list of sublists as per key/keys of sublist?
| Free embeddable forum powered by Nabble | Forum Help |