6 Stimmen

Wie kann ich das Maximum einer beliebigen Eigenschaft aus einer Liste in Scala erhalten?

Nehmen wir an, ich habe eine Klasse, die etwa so aussieht:

class Foo(Prop1:Int, Prop2:Int, Prop3:Int)
{
 ..
}

Und ich wollte eine Funktion erstellen, die den Maximalwert einer beliebigen Eigenschaft aus einer Liste von Foo s.

Zum Beispiel so:

def getMax(Foos:List[Foo], Property:??) = Foos.map(_.Property).sort(_ > _).head

Wenn ich anrufe getMax(myFooList, Prop1) wird der Wert des höchsten Prop1 aus dieser Liste von Foo s.

Meine Frage ist, wie kann ich das bewerkstelligen? Ich schätze, ich könnte eine Art von Enum (das Scala-Äquivalent) für die Property und machen eine match und führen Sie dann die map auf die entsprechende Eigenschaft, aber das scheint eine Menge Arbeit zu sein - ich müsste meine Aufzählung und die Funktion jedes Mal erweitern Foo umgestaltet wird.

Auch, nicht so wichtig, aber gibt es einen besseren Weg, um den maximalen Wert einer Liste als zu greifen, was ich tat?

16voto

Vasiliy Kevroletin Punkte 1168

Sie sollten den Standard maxBy Methode:

List(("a", 2), ("b", 3), ("c", 4)).maxBy(_._2)
=> (String, Int) = (c,4)

12voto

Alan Burlison Punkte 972

Sie können dies so einfach tun, indem Sie vorhandene Funktionen verwenden, dass das Schreiben eines eigenen getMax wahrscheinlich unnötig ist:

scala> val fooList = List(Foo(1,2),Foo(2,2),Foo(3,2),Foo(4,2))
fooList: List[Foo] = List(Foo(1,2), Foo(2,2), Foo(3,2), Foo(4,2))

scala> fooList.map(_.p2).max
res12: Int = 2

scala> fooList.map(_.p1).max
res13: Int = 4

Wenn Sie die Eigenschaft "getter" an anderer Stelle angeben wollten, könnten Sie dies wie folgt tun:

scala> def p1 = (f: Foo) => f.p1
p1: Foo => Int

scala> def p2 = (f: Foo) => f.p2
p2: Foo => Int

scala> fooList.map(p1).max
res14: Int = 4

scala> fooList.map(p2).max
res15: Int = 2

6voto

Jon Hoffman Punkte 842

Sie können einfach eine andere Funktion an getMax übergeben, um ihr mitzuteilen, wie die einzelnen Foo zugeordnet werden sollen:

case class Foo(p1:Int, p2:Int)

def getMax(foos:List[Foo], mapper:Foo=>Int):Int = foos.map(mapper).foldLeft(Math.MIN_INT)((i,m)=>m.max(i))

val fooList = List(Foo(1,2),Foo(2,2),Foo(3,2),Foo(4,2))

getMax(fooList,_.p1)
//-->  4

1voto

Flaviu Cipcigan Punkte 7153

Die Art und Weise, wie ich es tun würde, ist durch die Übergabe an die getMax() Methode eine Funktion, die weiß, wie man die gewünschte Eigenschaft aus Ihrer Foo d.h. etwas vom Typ Foo => Int .

Ich würde also wie folgt vorgehen:

scala> case class Foo(p1: Int, p2: Int, p3: Int)
defined class Foo

scala> def getMax(foos: List[Foo], prop: Foo => Int) = foos.map(prop).sort(_ > _).head
getMax: (List[Foo],(Foo) => Int)Int

scala> val lst = List(Foo(1,2,3), Foo(2,3,4), Foo(3,4,5))
lst: List[Foo] = List(Foo(1,2,3), Foo(2,3,4), Foo(3,4,5))

scala> getMax(lst, _.p1)
res0: Int = 3

scala> getMax(lst, _.p2)
res1: Int = 4

scala> getMax(lst, _.p3)
res2: Int = 5

-- Flaviu Cipcigan

1voto

Alexander Azarov Punkte 12552

Sie können Objekte verwenden, die von Product . Es ist einfacher und typsicherer, wenn Sie die Arität im Voraus kennen:

def getMax(foos: List[Product2[Int,Int]], f: Product2[Int,Int] => Int) = foos.map{f} ....

Dann sind Sie frei, sich zu ernähren getMax mit etwas wie Tuple z.B.

class Foo(val prop1: Int, val prop2: Int) extends Tuple2[Int, Int](prop1, prop2)
// this will duplicate values in an object actually.

getMax((new Foo(1,2)), _._2)    

oder das Recht erben von Product :

class Bar(val prop1: Int, val prop2: Int) extends Product2[Int, Int] {
  def _1 = prop1
  def _2 = prop2
}
val b = new Bar(2, 3)
getMax(List(b), _._2)

oder verwenden Sie einfach die Tupel von Scala:

getMax( (1,10) :: Nil, _._2)
getMax( List(1 -> 10), _._2)
// these are the same

Alles wird noch komplizierter, wenn man die Arität nicht vorher kennt, denn generische Product können Sie Elemente abrufen als Any nur (Siehe Product.productElement(n: Int) Methode) - damit verlieren Sie die Typsicherheit.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X