我有一个带有Foos系列的课程,我们称之为Bar。 Foo有许多我们想要在Bar级别聚合的返回数字的方法,如下所示:
def attribute1(inputs: Map[Int, Double]) =
foos.foldLeft(0d)((sum, foo) => sum + foo.attribute1(inputs(foo.id)))
为了聚合这些不同的属性,我可以使用
形式的n个函数 def attributeN(inputs: Map[Int, Double]) =
foos.foldLeft(0d)((sum, foo) => sum + foo.attributeN(inputs(foo.id)))
然而,这很难看 - 我讨厌重复迭代和求和的事实。我想抽象一下,所以我可以这样做:
def attribute1(inputs: Map[Int, Double]) = aggregate(Foo.attribute1, inputs)
private def aggregate(f: Double => Double) = foos.foldLeft(0d)((sum, foo) => sum + foo.f(inputs(foo.id)
当然,这不起作用,因为无法将Foo.attribute1作为函数引用 - 。不是函数实例。
我基本上偶然发现了各种解决方案,但是每个聚合方法的每个聚合方法都会产生代码,至少与我们没有帮助器的方式一样冗长或复杂,而且我留下了重复的迭代。
我可能只是希望在这里做太多,但我几乎可以肯定有一个优雅的方法来做到这一点是Scala逃避了我。所以,这里的任何Scala大师都会回答 - 提前感谢!
答案 0 :(得分:2)
我不确定我会得到你想要做的事情,但是在scala中这样一个返回数字的方法:
def attribute1 = 5
是一个功能。好吧,有点......它可以看作是类型为() => Int
的函数(不带参数,返回一个整数)。您只需使用无所不在的_
告诉scala将attribute1
转换为函数。
看看这有助于作为一个起点:
scala> class Foo {
| def attribute1=5
| def attribute2=2
| }
defined class Foo
scala> val foo=new Foo
foo: Foo = Foo@4cbba0bd
// test takes a function of type () => Int and just applies it (note
// the f() followed by () in the right-hand side to say we want to apply f
scala> def test(f: () => Int) = f()
test: (f: () => Int)Int
// the _ after foo.attribute1 tells scala that we want to use
// res2.attribute as a function, not take its value
scala> test(foo.attribute1 _)
res0: Int = 5
答案 1 :(得分:1)
所以基本上你要求的是一种在多个实例上解决特定方法的方法,对吧?如果是这样,它很容易解决:
trait Foo {
def id : Int
def attribute1( x : Double ) : Double
}
def aggregate( f : (Foo, Double) => Double, inputs : Map[Int, Double] ) =
foos.foldLeft(0d)( (sum, foo) => sum + f(foo, inputs(foo.id)) )
def aggregateAttribute1(inputs: Map[Int, Double]) =
aggregate(_.attribute1(_), inputs)
此解决方案的关键是_.attribute1(_)
,这是一种难以理解的写作方式
(foo, input) => foo.attribute1(input)
答案 2 :(得分:0)
在@Nikita的答案的基础上,如果你想从无聊的方法中删除更多的冗余,你可以讨论aggregate
方法:
def aggregate(f: (Foo, Double) => Double)(inputs: Map[Int, Double]): Double =
foos.foldLeft(0d)((sum, foo) => sum + f(foo, inputs(foo.id)))
def aggregateAttribute1: Map[Int, Double] => Double =
aggregate(_.attribute1(_))