我对Scala并不陌生,我使用var
编写了一些代码。我听说在Scala中不建议使用var
,所以我只想尝试使用val
。我研究并尝试了不同的方法,但无法获得与使用var
相同的结果。
def yearly_yield(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
val year = data(index)
var size = 0
var invYield = 0.0
for( j <- year)
if(j.isDefined)
size = size + 1
val amount = balance/size
for( i <- year.indices)
if (year(i).isDefined)
invYield += amount * year(i).get
balance + invYield.toLong
}
另一个是
def compound_yield(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
var newBalance = balance
for( i <- 0 until index)
newBalance = yearly_yield(data, newBalance, i)
newBalance
}
我认为我可以尝试对compound_yield
使用递归,但是我总是遇到错误。
答案 0 :(得分:2)
您可以在此处进行一些改进。首先,您的函数应该只返回一年的收益。如果您有年份列表,则可以对其进行迭代并逐年调用。其次,仅通过熟悉可以对集合执行的各种操作,就可以大大改善Scala代码。在这种情况下,您真正要做的只是折叠操作。通常,那些比Scala中的循环更可取。实际上,一旦您习惯了它们,相比之下,循环看起来就难看得多!此外,由于具有关联性,您可以在末尾乘以余额/大小而不是每次乘以。
def yearly_yield(data: List[Option[Double]], balance: Long): Long =
{
val year = data.flatten //Remove all the None's
(year.fold(0.0)(_+_)*balance/year.size).toLong
}
您的复合收益率操作只是将年收益率从左向右折叠。
def compound_yield(data: List[List[Option[Double]]], balance): Long =
data.foldLeft(0l)((balance, year) => balance * yearly_yield(year))
答案 1 :(得分:1)
像这样吗?
def yearly_yield(data :List[List[Option[Double]]]
,balance :Long, index: Int) :Long = {
val year :List[Double] = data(index).flatten
val amount :Long = balance/year.length
year.foldLeft(0.0){case (acc, d) => acc + amount * d}.toLong
}
def compound_yield(data :List[List[Option[Double]]]
,balance :Long, index: Int) :Long =
(0 until index).foldLeft(balance){ case (nb, idx) =>
yearly_yield(data, nb, idx)
}
答案 2 :(得分:0)
因此,每年都很简单:
def yearly(data: List[Option[Double]], balance: Long): Double = {
val interest = year.flatten
interest.map(_ * balance).sum / interest.size
}
您不需要发送所有的年份,而只是查看索引就可以索引(并且List
的随机访问不是您应该采用的任何一种方式),因此我相应地调整了参数。它也应该返回Double
而不是Long
。
.flatten
通过抛弃List[Option[Double]]
的那些选项,并将其他选项展开为List[Double]
,将None
变成Double
。
.map
遍历列表,并为每个元素调用函数(_
是参数的简写形式,即当前列表元素)。
然后我们将所有内容加在一起.sum
,然后除以大小(最后一部分似乎是错误的,我不知道您为什么要这样做BTW)。
请注意,.flatten
,.map
,.sum
和.size
分别遍历相同的列表,这可能被认为是浪费的。如果year
是几个月的清单,并且大约有12个月,那没什么关系,为了表达力,我敦促您以这种方式这样做。但是,如果我们谈论的是可能从远程存储中获取的数十亿个元素,则它可能变得令人望而却步。在这种情况下,总是有.foldLeft
:
val (total, size) = data.foldLeft((0, 0)) {
case ((total, size), Some(elem)) => (total + elem*balance, size + 1)
case (passThrough, _) => passThrough
}
total/size
此功能与第一个版本相同,但仅需通过列表一次即可。
.foldLeft
像.map
一样遍历列表,但是它不仅将当前列表元素传递给函数,还传递了上次返回的内容(或初始值,您将其作为参数提供给第一次调用),当前元素,最后返回的是最后一个函数执行的结果,而不是整个列表。
现在,要复利。您想从平衡开始,然后每年进行一次转换。 .foldLeft
就是这样做的:
data.foldLeft(balance) { case (balance, year) => balance + yearly(year, balance) }