Ответ 1
Ребята, вы заставили бедного вопрошающего найти "on" себя. Довольно потрепанный спектакль. Вы могли бы немного побрить его так:
list min Ordering[Int].on[(_,Int)](_._2)
Что еще слишком шумно, но что мы сейчас находимся.
В 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)
?
Ребята, вы заставили бедного вопрошающего найти "on" себя. Довольно потрепанный спектакль. Вы могли бы немного побрить его так:
list min Ordering[Int].on[(_,Int)](_._2)
Что еще слишком шумно, но что мы сейчас находимся.
В Scala 2.9 вы можете сделать list minBy { _._2 }
.
Одна вещь, которую вы можете сделать, это использовать более сжатый стандартный синтаксис типа tuple вместо использования 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
для max):
val min = list.sort( (a, b) => a._2 < b._2 ).first
который может быть дополнительно сокращен с использованием синтаксиса placeholder:
val min = list.sort( _._2 < _._2 ).first
Который, как вы сами написали, можно сократить до:
val min = list.sortBy( _._2 ).first
Но, как вы сами предложили sortBy
, я не уверен, что вы ищете что-то другое здесь.
Функция 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]] = [email protected]
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]] = [email protected]
list.min(Ordering.fromLessThan[(String, Int)](_._2 < _._2))
Это все еще слишком многословно. Я бы предположил, что это как val
или object
.
Вы всегда можете определить свое собственное неявное преобразование:
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)