简体   繁体   English

Scala vals vs vars

[英]Scala vals vs vars

I'm pretty new to Scala but I like to know what is the preferred way of solving this problem. 我对Scala很新,但我想知道解决这个问题的首选方法是什么。 Say I have a list of items and I want to know the total amount of the items that are checks. 假设我有一个项目列表,我想知道检查项目的总数。 I could do something like so: 我可以这样做:

val total = items.filter(_.itemType == CHECK).map(._amount).sum

That would give me what I need, the sum of all checks in a immutable variable. 这将给我我需要的东西,即不可变变量中所有检查的总和。 But it does it with what seems like 3 iterations. 但它看起来像是3次迭代。 Once to filter the checks, again to map the amounts and then the sum. 一旦过滤检查,再次映射金额,然后总和。 Another way would be to do something like: 另一种方法是做一些事情:

var total = new BigDecimal(0)
for (
    item <- items
    if item.itemType == CHECK
) total += item.amount

This gives me the same result but with 1 iteration and a mutable variable which seems fine too. 这给了我相同的结果,但是1次迭代和一个可变变量看起来也很好。 But if I wanted to to extract more information, say the total number of checks, that would require more counters or mutable variables but I wouldn't have to iterate over the list again. 但是,如果我想提取更多信息,比如支票总数,那就需要更多的计数器或可变变量,但我不必再次遍历列表。 Doesn't seem like the "functional" way of achieving what I need. 似乎不是实现我需要的“功能”方式。

var numOfChecks = 0
var total = new BigDecimal(0)
items.foreach { item =>
    if (item.itemType == CHECK) {
        numOfChecks += 1
        total += item.amount
    }
}

So if you find yourself needing a bunch of counters or totals on a list is it preferred to keep mutable variables or not worry about it do something along the lines of: 因此,如果您发现自己需要在列表中使用一堆计数器或总计,则首选保留可变变量或不担心它会执行以下操作:

val checks = items.filter(_.itemType == CHECK)
val total = checks.map(_.amount).sum
return (checks.size, total)

which seems easier to read and only uses vals 这似乎更容易阅读,只使用vals

Another way of solving your problem in one iteration would be to use views or iterators: 在一次迭代中解决问题的另一种方法是使用视图或迭代器:

items.iterator.filter(_.itemType == CHECK).map(._amount).sum

or 要么

items.view.filter(_.itemType == CHECK).map(._amount).sum

This way the evaluation of the expression is delayed until the call of sum . 这样,表达式的评估被推迟到sum的调用。

If your items are case classes you could also write it like this: 如果您的项目是案例类,您也可以这样写:

items.iterator collect { case Item(amount, CHECK) => amount } sum

I find that speaking of doing "three iterations" is a bit misleading -- after all, each iteration does less work than a single iteration with everything. 我发现说“三次迭代”有点误导 - 毕竟,每次迭代都比一次迭代完成的工作要少。 So it doesn't automatically follows that iterating three times will take longer than iterating once. 所以它不会自动跟随迭代三次将比迭代一次更长。

Creating temporary objects, now that is a concern, because you'll be hitting memory (even if cached), which isn't the case of the single iteration. 创建临时对象,现在是一个问题,因为你将打击内存(即使缓存),这不是单次迭代的情况。 In those cases, view will help, even though it adds more method calls to do the same work. 在这些情况下, view将有所帮助,即使它添加了更多方法调用来执行相同的工作。 Hopefully, JVM will optimize that away. 希望JVM能够优化它。 See Moritz 's answer for more information on views. 有关视图的更多信息,请参阅Moritz答案

You may use foldLeft for that: 您可以使用foldLeft

(0 /: items) ((total, item) => 
   if(item.itemType == CHECK) 
      total + item.amount 
   else 
      total
)

The following code will return a tuple (number of checks -> sum of amounts): 以下代码将返回一个元组(支票数 - >金额总和):

((0, 0) /: items) ((total, item) => 
   if(item.itemType == CHECK) 
      (total._1 + 1, total._2 + item.amount) 
   else 
      total
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM