[ACCEPTED]-How can I get the max of an arbitrary property from a list in Scala?-scala

Accepted answer
Score: 16

You should use standard maxBy method:

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

0

Score: 12

You can do this so simply using existing 4 functionality that writing your own getMax 3 is probably unnecessary:

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

If you wanted to 2 specify the property 'getter' elsewhere 1 you could do it like this:

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
Score: 6

You can simply pass another function into 1 getMax to instruct it how to map each Foo:

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
Score: 1

The way I would do it is by passing to the 4 getMax() method a function that knows how to extract 3 the required property out of your Foo, i.e. something 2 of type Foo => Int.

The way I would do it therefore 1 is as follows:

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

Score: 1

You can use objects inheriting from Product. It 9 will be simpler and more type safe if you 8 know arity in advance:

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

Then, you are free 7 to feed getMax with anything like Tuple, e.g.

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)    

or inherit 6 right from 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)

or simply use Scala's tuples:

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

Everything 5 will become more complicated in case you 4 do not know arity beforehand, because generic 3 Product will let you retrieve elements as Any only 2 (See Product.productElement(n: Int) method) -- thus you are loosing type 1 safety.

Score: 0

Please remember to check if the list is 1 not null, or the maxBy method will fail

val myList: List[Foo] = List();

val unsafeMax = myList.maxBy(_.propertyBar).propertyBar
// java.lang.UnsupportedOperationException: empty.max

val safeMax = if (myList.isEmpty) 0 else myList.maxBy(_.propertyBar).propertyBar;
safeMax == 0

More Related questions