Discussions related to Visual Prolog
Dalya
Posts: 1
Joined: 16 Mar 2020 19:30

### Sort a List of Functors

Hello everybody
please, is there someone who can teach me How can I sort a list of functors based on the fourth atom? For instance, if I have the following list[p('a', 2.5, 2, 4), p('b', 7.5, 3, 1)], then the sorted copy of this list, in ascending order, would be [p('b', 7.5, 3, 1), p('a', 2.5, 2, 4)].
Gukalov
VIP Member
Posts: 62
Joined: 5 Oct 2011 15:16

### Re: Sort a List of Functors

Generally, define your own COMPARATOR and use list::sortBy/2 or list::sortBy/3.
Usually, it's enough "meaningful" functor and list::sort/1 or list::sort/2.
Harrison Pratt
VIP Member
Posts: 443
Joined: 5 Nov 2000 0:01

### Re: Sort a List of Functors

Here's an example you can test for yourself as a console application.

Code: Select all

domains     pTerm = p(integer, integer, integer, integer).   clauses     run() :-         PTerms = [p(1, 2, 3, 4), p(3, 2, 1, 0), p(6, 3, 1, 2), p(2, 5, 7, 8)],         ValueN =             { (Index, P) = I :-                 p(A, B, C, D) = P,                 I = list::nth(Index, [A, B, C, D])             },         Pos = 2, % Note:  a 0-based index is used in the ValueN anonymous predicate         SortedPTerms = list::sortBy({ (L, R) = compare(ValueN(Pos, L), ValueN(Pos, R)) }, PTerms),         %         stdio::write("\n\nUNSORTED"),         foreach p(A, B, C, D) in PTerms do             stdio::writef("\n%,%,%,%", A, B, C, D)         end foreach,         stdio::write("\n\nSORTED on position index (0...N)", Pos),         foreach p(A, B, C, D) in SortedPTerms do             stdio::writef("\n%,%,%,%", A, B, C, D)         end foreach,         !,         _ = readline().
Gukalov
VIP Member
Posts: 62
Joined: 5 Oct 2011 15:16

### Re: Sort a List of Functors

Code: Select all

domains     pTerm = p(integer, integer, integer, integer).   clauses     run() :-         PTerms = [p(6, 3, 1, 3), p(1, 2, 3, 4), p(3, 2, 1, 0), p(6, 3, 1, 2), p(2, 5, 7, 8)],           Count = varM::new(0),         ValueN =             { (Index, P) = I :-                 p(A, B, C, D) = P,                 I = list::nth(Index, [A, B, C, D]),                 Count:value := Count:value + 1             },         Pos = 2, % Note:  a 0-based index is used in the ValueN anonymous predicate         Sorted1 = list::sortBy({ (L, R) = compare(ValueN(Pos, L), ValueN(Pos, R)) }, PTerms),         console::write(Sorted1, "... ", Count:value),           Count:value := 0,         Sorted2 = sortByFun(PTerms, {(X) = ValueN(Pos, X)}, core::ascending),         console::write("\n", Sorted2, "... ", Count:value),           console::write("\n........................................."),         _ = console::readLine().   class predicates     sortByFun : (Elem1*, core::function{Elem1, Elem2}, core::sortOrder) -> Elem1*. clauses     sortByFun(ListIn, Fun, Order) = ListOut :-         ToSort = list::map(ListIn, {(Lj) = core::tuple(Fun(Lj), Lj)}),         Sorted = list::sort(ToSort, Order),         ListOut = list::map(Sorted, {(core::tuple(_, B)) = B}).
[p(6,3,1,3),p(3,2,1,0),p(6,3,1,2),p(1,2,3,4),p(2,5,7,8)]... 20
[p(3,2,1,0),p(6,3,1,2),p(6,3,1,3),p(1,2,3,4),p(2,5,7,8)]... 5
.........................................
Thomas Linder Puls
VIP Member
Posts: 1400
Joined: 28 Feb 2000 0:01

### Re: Sort a List of Functors

If you just need a hardcoded sorting then it could look like this (assuming that the domain only contains the p functor):

Code: Select all

class predicates     sort4 : (pDom* L) -> pDom* S. clauses     sort4(L) = list::sortBy(compare4, L).   class predicates     compare4 : comparator{pDom}. clauses     compare4(p(_, _, _, A), p(_, _, _, B)) = compare(A, B).
Or your can "short-circuit" by using an anonymous predicate

Code: Select all

class predicates     sort4 : (pDom* List) -> pDom* Sort4. clauses     sort4(L) = list::sortBy({ (p(_, _, _, A), p(_, _, _, B)) = compare(A, B) }, L).
Regards Thomas Linder Puls
PDC
Gukalov
VIP Member
Posts: 62
Joined: 5 Oct 2011 15:16

### Re: Sort a List of Functors

Code: Select all

domains     pTerm = p(integer, integer, integer, integer).   clauses     run() :-         T1 = p(6, 3, 1, 3), T2 = p(3, 2, 1, 3), T3 = p(2, 5, 7, 3),         L1 = [ T1, T2, T3 ], L2 = [ T2, T1, T3 ], L3 = [ T3, T2, T1 ], L4 = [ T2, T3, T1 ],           foreach L in [ L1, L2, L3, L4 ] do             Sorted = list::sortBy(compare4, L),             console::write(Sorted, "\n")         end foreach,           console::write("........................................."),         _ = console::readLine().   class predicates     compare4 : comparator{pTerm}. clauses     compare4(p(_, _, _, A), p(_, _, _, B)) = compare(A, B).
[p(6,3,1,3),p(3,2,1,3),p(2,5,7,3)]
[p(3,2,1,3),p(6,3,1,3),p(2,5,7,3)]
[p(2,5,7,3),p(3,2,1,3),p(6,3,1,3)]
[p(3,2,1,3),p(2,5,7,3),p(6,3,1,3)]
.........................................
Several lists containing exactly the same elements (the same set) ordered by the same sorting.
Hm...
I don't know why, but I would prefer:

Code: Select all

class predicates     compare4 : comparator{pTerm}. clauses     compare4(p(_, _, _, A), p(_, _, _, B)) = compare(A, B) :-         A <> B,         !.       compare4(A, B) = compare(A, B).
Thomas Linder Puls
VIP Member
Posts: 1400
Joined: 28 Feb 2000 0:01

### Re: Sort a List of Functors

Yes, I agree on that. And if you intend to use the comparator in a map or set, it is crucial that the comparison covers all values.

Notice that now you can write:

Code: Select all

clauses     compare4(p(_, _, _, A4 | A), p(_, _, _, B4 | B)) = compareNotEqual(A4, B4) otherwise compare(A, B).
Or as an anonymous predicate:

Code: Select all

clauses     sort4(L) =         list::sortBy(             { (p(_, _, _, A4 | A), p(_, _, _, B4 | B)) =                 compareNotEqual(A4, B4)                     otherwise compare(A, B) %             },             L).
compareNotEqual is a predicate in core
Regards Thomas Linder Puls
PDC
Gukalov
VIP Member
Posts: 62
Joined: 5 Oct 2011 15:16

### Re: Sort a List of Functors

Thank you for all this "new words".
This is interesting.

core +

Code: Select all

predicates     compareBF : (Value Left, Value Right, function{Value, ToCompare}) -> compareResult.

Code: Select all

clauses     compareBF(L, R, CF) = compare(tuple(CF(L), L), tuple(CF(R), R)).
list +

Code: Select all

predicates     sortBF : (Elem*, function{Elem, ToCompare}) -> Elem*.     sortBF : (Elem*, function{Elem, ToCompare}, sortOrder) -> Elem*.

Code: Select all

clauses     sortBF(L, CF) = sortBF(L, CF, ascending).     sortBF(L, CF, Order) = sortBy({(A, B) = compareBF(A, B, CF)}, L, Order).
So, our example:

Code: Select all

Sorted = list::sortBF(List, {(p(_, _, _, V)) = V})
By the way, it used to be in VIP's class list some predicate sortEq once...
Or I'm mistaken?!)))