在 Scala 中扩展 Seq.sortBy
假设我有一份名单。
case class Name(val first: String, val last: String)
val names = Name("c", "B") :: Name("b", "a") :: Name("a", "B") :: Nil
如果我现在想按姓氏对该列表进行排序(如果这还不够,则按名字排序),这很容易完成。
names.sortBy(n => (n.last, n.first))
// List[Name] = List(Name(a,B), Name(c,B), Name(b,a))
但是,如果我想根据其他字符串排序规则对该列表进行排序,该怎么办?
不幸的是,以下方法不起作用:
val o = new Ordering[String]{ def compare(x: String, y: String) = collator.compare(x, y) }
names.sortBy(n => (n.last, n.first))(o)
// error: type mismatch;
// found : java.lang.Object with Ordering[String]
// required: Ordering[(String, String)]
// names.sortBy(n => (n.last, n.first))(o)
有什么方法可以让我更改顺序,而不必编写具有多个 if
–else< 的显式
sortWith
方法/code> 分支以便处理所有情况?
Say I have a list of names.
case class Name(val first: String, val last: String)
val names = Name("c", "B") :: Name("b", "a") :: Name("a", "B") :: Nil
If I now want to sort that list by last name (and if that is not enough, by first name), it is easily done.
names.sortBy(n => (n.last, n.first))
// List[Name] = List(Name(a,B), Name(c,B), Name(b,a))
But what, if I‘d like to sort this list based on some other collation for strings?
Unfortunately, the following does not work:
val o = new Ordering[String]{ def compare(x: String, y: String) = collator.compare(x, y) }
names.sortBy(n => (n.last, n.first))(o)
// error: type mismatch;
// found : java.lang.Object with Ordering[String]
// required: Ordering[(String, String)]
// names.sortBy(n => (n.last, n.first))(o)
is there any way that allow me to change the ordering without having to write an explicit sortWith
method with multiple if
–else
branches in order to deal with all cases?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,这几乎成功了:
另一方面,您也可以这样做:
这个本地定义的隐式将优先于
Ordering
对象上定义的隐式。Well, this almost does the trick:
On the other hand, you can do this as well:
This locally defined implicit will take precedence over the one defined on the
Ordering
object.一种解决方案是扩展隐式使用的 Tuple2 排序。不幸的是,这意味着在代码中写出
Tuple2
。One solution is to extend the otherwise implicitly used Tuple2 ordering. Unfortunately, this means writing out
Tuple2
in the code.我不能 100% 确定您认为
collator
应该具有哪些方法。但是,如果您在案例类上定义排序,则具有最大的灵活性:
但您也可以提供从字符串排序到名称排序的隐式转换:
然后您可以使用任何字符串排序对名称进行排序:
编辑:一个方便的技巧,以防万一,如果你想按 N 个东西排序并且你已经在使用比较,你可以将每个东西乘以 3^k (第一个到顺序乘以最大的3) 的幂并相加。
如果您的比较非常耗时,您可以轻松添加级联比较:
然后
(只需小心嵌套它们
x tiebreak ( y tiebreak ( z tiebreak w ) ) )
这样您就不会连续进行多次隐式转换)。(如果您确实需要快速比较,那么您应该手动将其全部写出来,或者将顺序打包在一个数组中并使用 while 循环。我假设您对性能并不那么渴望。)
I'm not 100% sure what methods you think
collator
should have.But you have the most flexibility if you define the ordering on the case class:
but you can also provide an implicit conversion from a string ordering to a name ordering:
and then you can use any String ordering to sort Names:
Edit: A handy trick, in case it wasn't apparent, is that if you want to order by N things and you're already using compare, you can just multiply each thing by 3^k (with the first-to-order being multiplied by the largest power of 3) and add.
If your comparisons are very time-consuming, you can easily add a cascading compare:
and then
(just be careful to nest them
x tiebreak ( y tiebreak ( z tiebreak w ) ) )
so you don't do the implicit conversion a bunch of times in a row).(If you really need fast compares, then you should write it all out by hand, or pack the orderings in an array and use a while loop. I'll assume you're not that desperate for performance.)