在 Scala 中,如何将 Ordering[T] 与 List.min 或 List.max 一起使用并保持代码可读性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2190511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In Scala, how to use Ordering[T] with List.min or List.max and keep code readable
提问by huynhjl
In Scala 2.8, I had a need to call List.min and provide my own compare function to get the value based on the second element of a Tuple2. I had to write this kind of code:
在 Scala 2.8 中,我需要调用 List.min 并提供我自己的比较函数来获取基于 Tuple2 的第二个元素的值。我不得不写这样的代码:
val list = ("a", 5) :: ("b", 3) :: ("c", 2) :: Nil
list.min( new Ordering[Tuple2[String,Int]] {
def compare(x:Tuple2[String,Int],y:Tuple2[String,Int]): Int = x._2 compare y._2
} )
Is there a way to make this more readable or to create an Ordering out of an anonymous function like you can do with list.sortBy(_._2)?
有没有办法让它更具可读性,或者像你一样从匿名函数中创建一个 Ordering list.sortBy(_._2)?
回答by missingfaktor
In Scala 2.9, you can do list minBy { _._2 }.
在 Scala 2.9 中,您可以执行list minBy { _._2 }.
回答by psp
C'mon guys, you made the poor questioner find "on" himself. Pretty shabby performance. You could shave a little further writing it like this:
来吧伙计们,你让这个可怜的提问者发现了自己。相当简陋的表现。你可以像这样写得更远一点:
list min Ordering[Int].on[(_,Int)](_._2)
Which is still far too noisy but that's where we are at the moment.
这仍然太吵了,但这就是我们目前所处的位置。
回答by Fabian Steeg
One thing you can do is use the more concise standard tuple type syntax instead of using Tuple2:
您可以做的一件事是使用更简洁的标准元组类型语法,而不是使用Tuple2:
val min = list.min(new Ordering[(String, Int)] {
def compare(x: (String, Int), y: (String, Int)): Int = x._2 compare y._2
})
Or use reduceLeftto have a more concise solution altogether:
或者使用reduceLeft一个更简洁的解决方案:
val min = list.reduceLeft((a, b) => (if (a._2 < b._2) a else b))
Or you could sort the list by your criterion and get the firstelement (or lastfor the max):
或者您可以根据您的标准对列表进行排序并获取first元素(或last最大值):
val min = list.sort( (a, b) => a._2 < b._2 ).first
Which can be further shortened using the placeholder syntax:
可以使用占位符语法进一步缩短:
val min = list.sort( _._2 < _._2 ).first
Which, as you wrote yourself, can be shortened to:
正如您自己写的那样,可以缩短为:
val min = list.sortBy( _._2 ).first
But as you suggested sortByyourself, I'm not sure if you are looking for something different here.
但是正如您sortBy自己建议的那样,我不确定您是否在这里寻找不同的东西。
回答by retronym
The function Ordering#onwitnesses the fact that Orderingis a contra-variant functor. Others include Comparator, Function1, Comparableand scalaz.Equal.
该函数Ordering#on见证了Ordering一个逆变函子的事实。其他的还包括Comparator,Function1,Comparable和scalaz.Equal。
Scalaz provides a unified view on these types, so for any of them you can adapt the input with value contramap f, or with symbolic denotation, value ? f
Scalaz 提供了关于这些类型的统一视图,因此对于它们中的任何一种,您都可以使用value contramap f或符号表示来调整输入,value ? f
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> val ordering = implicitly[scala.Ordering[Int]] ? {x: (_, Int) => x._2}
ordering: scala.math.Ordering[Tuple2[_, Int]] = scala.math.Ordering$$anon@34df289d
scala> List(("1", 1), ("2", 2)) min ordering
res2: (java.lang.String, Int) = (1,1)
Here's the conversion from the Ordering[Int]to Ordering[(_, Int)]in more detail:
下面是从Ordering[Int]到Ordering[(_, Int)]的更详细的转换:
scala> scalaz.Scalaz.maContravariantImplicit[Ordering, Int](Ordering.Int).contramap { x: (_, Int) => x._2 }
res8: scala.math.Ordering[Tuple2[_, Int]] = scala.math.Ordering$$anon@4fa666bf
回答by Daniel C. Sobral
list.min(Ordering.fromLessThan[(String, Int)](_._2 < _._2))
Which is still too verbose, of course. I'd probably declare it as a valor object.
当然,这仍然太冗长了。我可能会将其声明为 a valor object。
回答by Mitch Blevins
You could always define your own implicit conversion:
您始终可以定义自己的隐式转换:
implicit def funToOrdering[T,R <% Ordered[R]](f: T => R) = new Ordering[T] {
def compare(x: T, y: T) = f(x) compare f(y)
}
val list = ("a", 5) :: ("b", 3) :: ("c", 2) :: Nil
list.min { t: (String,Int) => t._2 } // (c, 2)
EDIT: Per @Dario's comments.
编辑:根据@Dario 的评论。
Might be more readable if the conversion wasn't implicit, but using an "on" function:
如果转换不是隐式的,而是使用“on”函数,则可能更具可读性:
def on[T,R <% Ordered[R]](f: T => R) = new Ordering[T] {
def compare(x: T, y: T) = f(x) compare f(y)
}
val list = ("a", 5) :: ("b", 3) :: ("c", 2) :: Nil
list.min( on { t: (String,Int) => t._2 } ) // (c, 2)

