如何从Scala中的列表中获取任意属性的最大值?

时间:2009-09-18 18:33:43

标签: scala

假设我有一个看起来像这样的课程:

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

我想创建一个函数,从Foo列表中获取某些任意属性的最大值。

像这样:

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

如果我致电getMax(myFooList, Prop1),它会从此Prop1列表中返回最高Foo的值。

我的问题是,我怎样才能做到这一点?我想我可以为Property创建某种枚举(scala等价物)并执行match然后在相应的属性上运行map,但这似乎很多工作 - 每次Foo重构时,我都必须扩展我的枚举和函数。

此外,不是那么重要,但有没有更好的方法来获取列表的最大值然后我做了什么?

6 个答案:

答案 0 :(得分:12)

您可以这样做,只需使用现有功能,编写自己的getMax可能是不必要的:

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

如果你想在其他地方指定属性'getter',你可以这样做:

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

答案 1 :(得分:9)

您应该使用标准maxBy方法:

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

答案 2 :(得分:6)

您可以简单地将另一个函数传递给getMax,以指示它如何映射每个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

答案 3 :(得分:1)

我这样做的方法是向getMax()方法传递一个知道如何从Foo中提取所需属性的函数,即类型Foo => Int。< / p>

我这样做的方式如下:

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

答案 4 :(得分:1)

您可以使用从Product继承的对象。如果你事先知道arity,它会更简单,更安全:

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

然后,您可以getMaxTuple提供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) ,例如

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) 继承:

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

或只是使用Scala的元组:

Product

如果您事先不知道arity,一切都会变得更加复杂,因为通用Any只允许您将元素检索为Product.productElement(n: Int)(请参阅{{1}}方法) - 因此您就是失去类型安全。

答案 5 :(得分:0)

请记得检查列表是否不为空,否则maxBy方法会失败

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