代码之家  ›  专栏  ›  技术社区  ›  ryeguy

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

  •  5
  • ryeguy  · 技术社区  · 16 年前

    假设我有一个类似这样的类:

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

    我想创建一个函数,从一个 Foo s

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

    如果我打电话 getMax(myFooList, Prop1) Prop1

    Property 然后做一个 match map 在适当的属性上,但这似乎是一个很大的工作-我必须每次扩展我的枚举和函数 是重构的。

    还有,没那么重要,但是有没有比我做的更好的方法来获取列表的最大值呢?

    5 回复  |  直到 16 年前
        1
  •  15
  •   Vasiliy Kevroletin    11 年前

    你应该使用标准的 maxBy 方法:

    List(("a", 2), ("b", 3), ("c", 4)).maxBy(_._2)
    => (String, Int) = (c,4)
    
        2
  •  12
  •   Alan Burlison    13 年前

    您只需使用现有功能即可完成此操作,而编写自己的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
    

    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
    
        3
  •  6
  •   Jon Hoffman    16 年前

    您只需将另一个函数传递到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
    
        4
  •  1
  •   Flaviu Cipcigan    16 年前

    我会这样做的方式是通过传递给 getMax() Foo ,即某种类型的东西 Foo => Int .

    因此,我的做法如下:

    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

        5
  •  1
  •   Alexander Azarov    16 年前

    可以使用继承自的对象 Product . 如果您事先知道arity,它将更简单、更安全:

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

    然后,你就可以自由进食了 getMax Tuple ,例如。

    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)    
    

    或从中继承权利 产品

    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)
    

    或者简单地使用Scala的元组:

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

    将允许您按以下方式检索元素: Any Product.productElement(n: Int) 方法)--因此您失去了类型安全性。

        6
  •  0
  •   Thiago Mata    4 年前

    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
    
    推荐文章