代码之家  ›  专栏  ›  技术社区  ›  huynhjl bhericher

在scala中,如何对list.min或list.max使用ordering[t]并保持代码可读

  •  27
  • huynhjl bhericher  · 技术社区  · 15 年前

    在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 
    } )
    

    有没有办法使它更具可读性,或者像使用 list.sortBy(_._2) ?

    6 回复  |  直到 15 年前
        1
  •  29
  •   psp    15 年前

    伙计们,你们让那个可怜的发问者自己找到了答案。相当寒酸的表演。你可以再这样写一点:

    list min Ordering[Int].on[(_,Int)](_._2)
    

    这仍然是太吵了,但这是我们目前的位置。

        2
  •  33
  •   missingfaktor Kevin Wright    13 年前

    在scala 2.9中,您可以 list minBy { _._2 } .

        3
  •  10
  •   Fabian Steeg    15 年前

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

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

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

    val min = list.reduceLeft((a, b) => (if (a._2 < b._2) a else b))
    

    或者你可以根据自己的标准对列表进行排序,然后得到 first 元素(或) last 对于最大值):

    val min = list.sort( (a, b) => a._2 < b._2 ).first
    

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

    val min = list.sort( _._2 < _._2 ).first
    

    正如你自己写的,它可以缩短为:

    val min = list.sortBy( _._2 ).first
    

    但正如你所建议的 sortBy 你自己,我不确定你是否在这里寻找不同的东西。

        4
  •  7
  •   missingfaktor Kevin Wright    13 年前

    函数 Ordering#on 见证了一个事实 Ordering 是反变函子。其他包括 Comparator , Function1 , Comparable scalaz.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)
    

    这是从 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
    
        5
  •  5
  •   Daniel C. Sobral    15 年前
    list.min(Ordering.fromLessThan[(String, Int)](_._2 < _._2))
    

    当然,还是太冗长了。我可能会宣布 val object .

        6
  •  3
  •   Mitch Blevins    15 年前

    您可以定义自己的隐式转换:

    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)
    

    编辑:根据@dario的评论。

    如果转换不是隐式的,而是使用“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)