【问题标题】:Scala vals vs varsScala vals 与 vars
【发布时间】:2010-11-26 03:31:29
【问题描述】:

我对 Scala 还很陌生,但我想知道解决这个问题的首选方法是什么。假设我有一个项目清单,我想知道支票项目的总金额。我可以这样做:

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

这将给我我需要的东西,一个不可变变量中所有检查的总和。但它看起来像是 3 次迭代。一次过滤支票,再次映射金额,然后是总和。另一种方法是执行以下操作:

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

这给了我相同的结果,但有 1 次迭代和一个看起来也不错的可变变量。但是如果我想提取更多信息,比如检查的总数,那将需要更多的计数器或可变变量,但我不必再次遍历列表。似乎不是实现我需要的“功能”方式。

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

因此,如果您发现自己需要在列表中包含一堆计数器或总计,是保留可变变量还是不用担心它,请按照以下方式进行操作:

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

这似乎更容易阅读并且只使用vals

【问题讨论】:

  • for 表达式实际上编译为mapfilterforeach,所以它相当于你的第一个示例。
  • 这不再准确:for comprehension 使用 withFilter,而不是 filter,除非集合没有 withFilter 方法。

标签: scala


【解决方案1】:

在一次迭代中解决问题的另一种方法是使用视图或迭代器:

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

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

这样,表达式的计算会延迟到sum的调用。

如果你的项目是案例类,你也可以这样写:

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

【讨论】:

    【解决方案2】:

    我发现说做“三次迭代”有点误导——毕竟,每次迭代所做的工作都比对所有事情都进行一次迭代要少。因此,不会自动得出迭代 3 次会比迭代一次花费更长的时间。

    创建临时对象,现在 是一个问题,因为您将使用内存(即使已缓存),而单次迭代并非如此。在这些情况下,view 会有所帮助,即使它添加了更多方法调用来完成相同的工作。希望 JVM 会优化它。有关视图的更多信息,请参阅 Moritzanswer

    【讨论】:

      【解决方案3】:

      您可以为此使用foldLeft

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

      以下代码将返回一个元组(支票数量 -> 金额总和):

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

      【讨论】:

      • 忘了折叠/这会将我的所有数据返回到一个漂亮的元组中
      猜你喜欢
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-18
      • 1970-01-01
      • 2020-07-15
      • 1970-01-01
      • 2016-11-09
      相关资源
      最近更新 更多