如何在 OCL 中按两个参数排序?

How to SortBy two parameters in OCL?

我需要按两个参数对人物集合进行排序,先按姓氏,然后按姓名。我怎样才能在 OCL 中做这样的事情?

sortedBy 函数使用函数体中表达的标准和每个收集结果之间的 < 关系对元素进行排序。

在你的例子中,假设你有一个 surname 属性,下面的语句将对收集的每个姓氏使用 < 运算符对集合 c 进行排序(所以 < 在字符串上):

c->sortedBy(p | p.surname)

一个想法可能是使用连接在一起的姓氏和名称来计算一个唯一的字符串。因此,如果您有:

  • 乔治·史密斯
  • 加里·史密斯
  • 乔治·斯马特

比较将在 "Smith_George"、"Smith_Garry" 和 "Smath_George" 之间进行,并按照字典顺序排列为:

  1. 乔治·史密斯 (Smath_George)
  2. 加里·史密斯 (Smith_Garry)
  3. 乔治·史密斯 (smith_George)

最后,OCL 请求将是(假设 surnamename 作为现有属性):

c->sortedBy(p | p.surname + '_' + p.name)

这个小技巧可以完成工作,但它不是 "exactly" sortedBy 的两个参数比较。

OCL sortedBy(lambda) 似乎与 Java 的 sort(comparator) 非常不同,显然需要对象的投影作为排序的度量。但是,如果投影是自我的,则您具有不同的 Java 功能。因此,如果您执行 sortedBy(p | p) 排序取决于 p.

的 < 操作

为了促进这一点,未来 OCL 的 Eclipse OCL 原型引入了一个带有 compareTo 方法的 OclComparable 类型,只要您的自定义类型扩展了 OclComparable 类型,就可以实现所有关系操作。

(具有 zero() 和 sum() 操作的类似 OclSummable 一般支持 Collection::sum();例如,String 将 sum 实现为串联。)

谢谢你启发了我。我刚刚提出 http://issues.omg.org/browse/OCL25-213 其文本是:

sortedBy 迭代为排序问题提供了一个优雅的解决方案,其中排序度量是已排序对象的投影。因此 sortedBy(p|p.name) 或只是 sortedBy(name) 是简短的,并且避免了在涉及两个对象比较的更传统的说明中出现拼写错误的机会。对于具有重要指标的大型集合,自然解决方案很可能是一种有效的解决方案。

然而,sortedBy 解决方案不熟悉,因此对于新手来说会造成混淆,并且不适合可能需要构建人工复合单键的多键排序。

一个解决方案可能是提供一个更传统的迭代器,例如 sort(p1, p2 | comparison-expression) 允许两个键排序:

sort(p1, p2 | 让 diff1 = p1.key1.compareTo(p2.key1) 在 如果 diff1 <> 0 diff 1 else p1.key2.compareTo(p2.key2) endif)

然而,它的可读性很差,并且容易出现错别字。

或者,使用元组值度量的 sortedBy 可能支持多个键,如:

sortedBy(元组{first=key1,second=key2})

(元组部分名称的字母顺序决定优先级。)

(由于 sortedBy 声明清晰紧凑,低效的 small/trivial 实现可以优化为它们的 sort() 等价物。)