В Scala, как использовать Упорядочивание [T] с List.min или List.max и сохранить код читаемым

В 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)?

28
задан huynhjl 3 February 2010 в 08:14
поделиться

5 ответов

Это ответ POSIX, который действительно делает то, что требует проблема:)

Он не будет работать на некоторых архитектурах/компиляторах, но это делает здесь.

#include <stdio.h>

void
change () {

    void _change();
    _change();
}
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
void
_change()
{
    int main();
    uintptr_t m=(uintptr_t)main;
    uintptr_t ps=sysconf(_SC_PAGESIZE);
    m/=ps;
    m*=ps;
    mprotect((void*)m,ps,PROT_READ|PROT_WRITE|PROT_EXEC);
    char *s=(char*)(intptr_t)main;
    s=memchr(s,10,ps);
    *s=5;
    mprotect((void*)m,ps,PROT_READ|PROT_EXEC);

}

int
main() {
    int i=5;
    change();
    i=10;
    printf ("%d\n",i);
    return 0;
}

EDIT: Это должно сделать его более надежным для людей с бойкотирующими заголовками.

-121--2227029-

Можно записать функцию в файл .profile для переключения псевдонимов

function toggle-ruby() {
  if [ "$1" == "1.9" ]; then
    alias ruby=/opt/local/bin/ruby1.9
  else
    alias ruby=/opt/local/bin/ruby1.8
  fi
}

, а затем выполнить команду

toggle-ruby 1.9

или

toggle-ruby 1.8

для переключения назад и вперед.

-121--965164-

Вы заставили беднягу найти «на» себя. Довольно потрепанный исполнительный. Вы могли бы побриться немного дальше писать это так:

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

Что еще слишком шумно, но это то, где мы находимся в данный момент.

29
ответ дан 28 November 2019 в 02:25
поделиться

Вы всегда можете определить свое собственное неявное преобразование:

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)

РЕДАКТИРОВАТЬ: Комментарии Per @ 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)
3
ответ дан 28 November 2019 в 02:25
поделиться

Одно дело вы можете использовать более сжатый стандартный синтаксис типа кортежа вместо того, чтобы использовать 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 for the max):

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, я не уверен, что вы ищете здесь что-то другое.

10
ответ дан 28 November 2019 в 02:25
поделиться
list.min(Ordering.fromLessThan[(String, Int)](_._2 < _._2))

Что, конечно, все еще слишком многословно. Я, вероятно, объявил бы это как val или object.

5
ответ дан 28 November 2019 в 02:25
поделиться

Функция Ordering # на свидетельствует о том, что 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)

Вот преобразование из Порядок [Int] в Порядок [(_, 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
7
ответ дан 28 November 2019 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: