1

我有一个包含 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 大师 - 在此先感谢!

4

3 回答 3

2

我不确定我是否得到您想要做的事情,但在 scala 中,有一个这样的数字返回方法:

def attribute1 = 5

是一个函数。嗯,有点……它可以看作是一个有类型的函数() => Int(不带参数,返回一个整数)。你只需要使用无所不在_的告诉 scalaattribute1变成一个函数。看看这是否有助于作为起点:

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
于 2013-09-19T16:12:29.787 回答
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)
于 2013-09-19T17:29:51.993 回答
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(_))
于 2013-09-20T16:11:00.873 回答