« Return to Thread: How to sort list of sublists as per key/keys of sublist?

Re: How to sort list of sublists as per key/keys of sublist?

by Lev777 :: Rate this Message:

Reply to Author | View in Thread



On Thu, Jun 11, 2009 at 2:00 AM, Richard O'Keefe <ok@...> wrote:

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

I assume that that's a table of facts, so

:- 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?

While selecting a proper structure for data representation I read a newsletter: http://www.ainewsletter.com/newsletters/aix_0309.htm#ontology
and did not know that in prolog (=)/2 is not supported as (-)/2. (I am learning prolog while working on my very first project in this language).
 

[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?

My data is like:

object(type1, id, title, [
  prop1-val1,
  prop2-val2,...
  propN-valN
]).
 
Data come from external source in form of XML, and I have no idea how many properties will be, but I know that there will be type, id and title which will form a unique key.
XML I am parsing using PHP to Prolog (thus avoiding dealing with SQL database structures and writing wrapping classes and other 'gifts' of OOP).
 



I have a predicate which finds all objects with particular key, e.g. objects with color='blue'.

The second thing that strikes me is that what you really have
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).

During my work on this project I have tried several structures. And first one was binary relation. But I found it difficult for me to write predicates for querying it, as I have complex properties, like e.g. prop(obj, val1, val2, val3...) and each value may be connectedc to another property etc.
That's why I have selected above structure where each  object has three basic common properties and list of other properties. If some of properties are compound my external script generates new objects for them.   

However I think that RDF would be better in this case....I will do it in RDF when I learn it :-)
 

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)


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

There are several ways to do it.
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. 
I have rewritten structure of terms, query predicates and now they work much faster and speed is suitable for my php application..   
 
Best Regards
Levan Cheishvili





Thanks!



 « Return to Thread: How to sort list of sublists as per key/keys of sublist?