Reputation: 307
I need to sort the collection of Persons by two parameters, by Surnames and after by Names. How can I do something like this in OCL?
Upvotes: 1
Views: 751
Reputation: 1498
Thanks you inspired me. I just raised http://issues.omg.org/browse/OCL25-213 whose text is:
The sortedBy iteration provides an elegant solution to a sort problem in which the sort metric is a projection of the sorted object. Thus sortedBy(p|p.name) or just sortedBy(name) is short and avoids the opportunities for typos from a more conventional exposition involving comparison of two objects. The natural solution may well be an efficient one for large collections with non-trivial metrics.
However the sortedBy solution is unfamiliar and so confusing for newcomers and unsuitable for multi-key sorting for which an artificial compound single key may need to be constructed.
One solution might be to provide a more conventional iterator such as sort(p1, p2 | comparison-expression) allowing a two key sort:
sort(p1, p2 | let diff1 = p1.key1.compareTo(p2.key1) in if diff1 <> 0 the diff 1 else p1.key2.compareTo(p2.key2) endif)
However this has poor readability and ample opportunities for typos.
Alternatively sortedBy with a Tuple-valued metric might support multiple keys as:
sortedBy(Tuple{first=key1,second=key2})
(The alphabetical order of the Tuple part names determines the priority.)
(Since sortedBy is declaratively clear and compact, inefficient small/trivial implementations can be optimized to their sort() equivalents.)
Upvotes: 1
Reputation: 1498
The OCL sortedBy(lambda) appears to be very different to Java's sort(comparator) apparently requiring a projection of the objects as the metric for sorting. However if the projection is self, you have a different Java functionality. Therefore if you do sortedBy(p | p) the sorting is dependent on the < operation for p.
To facilitate this, the Eclipse OCL prototype of a future OCL introduces an OclComparable type with a compareTo method enabling all relational operations to be realized provided your custom type extends the OclComparable type.
(A similar OclSummable with zero() and sum() operates supports Collection::sum() generically; e.g. String realizes sum as a concatenation.)
Upvotes: 0
Reputation: 1536
The sortedBy
function sorts elements using a the criteria expressed in its body and a <
relationship between each gathered result.
In your case, assuming that you have a surname
attribute, the following statement will sort the collection c
using the <
operator on each surname gathered (so a <
on strings):
c->sortedBy(p | p.surname)
An idea could be to compute a unique string using the surname and the name concatenated toghether. Thus, if you have:
The comparison would be done between "Smith_George", "Smith_Garry" and "Smath_George" and would be ordered, following the lexicographical order, to:
Finally, the OCL request would be (assuming surname
and name
as existing attributes):
c->sortedBy(p | p.surname + '_' + p.name)
This little trick does the job, but it is not "exactly" a two parameters comparison for sortedBy.
Upvotes: 1