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
Active Member
Posts: 44
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: 379
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,
!,
Gukalov
Active Member
Posts: 44
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........................................."),

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: 1295
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
Active Member
Posts: 44
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("........................................."),

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: 1295
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
Active Member
Posts: 44
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?!)))