在Scala中,如何在List.min或List.max中使用Ordering [T]并保持代码可读

huy*_*hjl 28 scala

在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 
} )
Run Code Online (Sandbox Code Playgroud)

有没有办法让这个更具可读性,或者像你可以用匿名函数创建一个Ordering list.sortBy(_._2)

mis*_*tor 36

在Scala 2.9中,你可以做到list minBy { _._2 }.


psp*_*psp 29

来吧,伙计们,你让那个可怜的提问者"自己"找到了.相当破旧的表现.你可以再刮一下这样写:

list min Ordering[Int].on[(_,Int)](_._2)
Run Code Online (Sandbox Code Playgroud)

哪个仍然太吵了,但这就是我们现在所处的位置.

  • `list min Ordering.by((_:(_,Int))._ 2)` (7认同)

Fab*_*eeg 10

您可以做的一件事是使用更简洁的标准元组类型语法而不是使用Tuple2:

val min = list.min(new Ordering[(String, Int)] { 
  def compare(x: (String, Int), y: (String, Int)): Int = x._2 compare y._2 
})
Run Code Online (Sandbox Code Playgroud)

或者使用reduceLeft一个更简洁的解决方案:

val min = list.reduceLeft((a, b) => (if (a._2 < b._2) a else b))
Run Code Online (Sandbox Code Playgroud)

或者您可以按标准对列表进行排序并获取first元素(或last最大值):

val min = list.sort( (a, b) => a._2 < b._2 ).first
Run Code Online (Sandbox Code Playgroud)

可以使用占位符语法进一步缩短:

val min = list.sort( _._2 < _._2 ).first
Run Code Online (Sandbox Code Playgroud)

正如您自己写的那样,可以缩短为:

val min = list.sortBy( _._2 ).first
Run Code Online (Sandbox Code Playgroud)

但正如你sortBy自己建议的那样,我不确定你是否在寻找不同的东西.

  • 我没有查看库代码,但我更喜欢使用`min`的原因是我认为它会在时间上是线性的,而`sortBy`将是o(n.log(n)).我还认为使用一个名为`min`的方法可以使意图更清晰,尽管`list.sortBy(_._ 2).first`也很清楚. (2认同)

ret*_*nym 7

该功能Ordering#on见证了Ordering一个反变异函子的事实.其他的还包括Comparator,Function1,Comparablescalaz.Equal.

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$2@34df289d

scala> List(("1", 1), ("2", 2)) min ordering  
res2: (java.lang.String, Int) = (1,1)
Run Code Online (Sandbox Code Playgroud)

下面是从转换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$2@4fa666bf
Run Code Online (Sandbox Code Playgroud)

  • Scalaz是黑带级别的东西.对我来说现在尝试可能是危险的...但它可能为我提供了一个与Scalaz相关的角度.所以统一视图是由"隐式"提供的?什么是`comap`?它与`map`类似吗?我在哪里可以找到更多文档? (2认同)
  • 根据Scalaz 6更新了答案. (2认同)

Dan*_*ral 5

list.min(Ordering.fromLessThan[(String, Int)](_._2 < _._2))
Run Code Online (Sandbox Code Playgroud)

当然,这仍然过于冗长.我可能会把它宣布为valobject.