具有缺失值的列表上的算术运算

时间:2012-11-25 02:55:56

标签: list scala math missing-data

我正在尝试对可能包含缺失值的列表进行一些算术运算。 到目前为止,我用Option [Int]代表我的列表:

val mylist=List( Option(4), Option(8), None )

通过这种表示,我可以轻松地在列表上应用一个函数(比如乘以2):

scala> mylist.map(_.map(_*2))
res2: List[Option[Int]] = List(Some(8), Some(16), None)

然而,这看起来比它需要的更复杂,所以我想知道我是否遗漏了一些东西。

另外,我无法弄清楚如何写总和。我想应该可以使用(大)减少表达式...

所以,我想知道是否:

  • 列表[Option [Int]]是此用例的良好表示
  • mylist.map(_.map(_*2))是映射的最佳方式
  • 有一种简单的方法可以做一笔钱吗?

5 个答案:

答案 0 :(得分:1)

嗯,这不是我自己使用的模式,但如果值“缺失”,则Option是合适的。但是List可能不是。在List中,这个位置通常不是你应该依赖的东西,因为它不是随机访问。也许Vector会更好,或者你需要考虑一种更好的问题建模方法,即不是缺少值的列表。

你可以很好地使用for-expressions来处理Option

for (o <- mylist; x <- o) yield x * 2

或压扁列表:

mylist.flatten.map(_ * 2)

总结一下:

mylist.flatten.sum

答案 1 :(得分:1)

  
      
  • 列表[Option [Int]]是此用例的良好表示
  •   

是否可以使用flatMap更早地展平它?例如,如果使用map创建此列表,则可以使用flatMap而不是缺少值。我的建议是,如果可能,甚至不代表缺失值。如果您需要代表它们,选项是理想的。

  
      
  • mylist.map(_.map(_*2))是映射的最佳方式
  •   
  • 有一种简单的方法可以做一笔钱吗?
  •   

嵌套地图可能更可取。你也可以foldLeft

如果您需要在sum / product之外做一些事情,

foldLeft也会有所帮助。

scala> val mylist=List( Option(4), Option(8), None )
mylist: List[Option[Int]] = List(Some(4), Some(8), None)

scala> mylist.foldLeft(0){
     |   case (acc, Some(i)) => acc + i 
     |   case (acc, _) => acc
     | }
res7: Int = 12

scala> (0 /: mylist) {
     |   case (acc, Some(i)) => acc + i 
     |   case (acc, _) => acc
     | }
res8: Int = 12

scala> (0 /: mylist) {
     |   case (acc, Some(i)) => acc - (i * 2)
     |   case (acc, _) => acc
     | }
res16: Int = -24

答案 2 :(得分:0)

  

所以,我想知道是否:

     

List [Option [Int]]是此用例的良好表示

选项绝对是表达缺失值的首选方式。您还可以考虑将其更改为List[(Int, Int)],其中第一个元素表示原始列表中的位置,第二个元素表示值。

  

mylist.map(_.map(_*2))是映射的最佳方式

在我看来,没有更短或更清晰的表达方式。 (你有两个“级别”,这就是你需要两张地图的原因!)根据我建议的数据结构,这将转变为mylist.map(t => (t._1, t._2*2))

  

有一种简单的方法来做一笔钱吗?

没有比om-nom-nom更容易的方法。使用我的数据结构,它将是mylist.map(_._2).sum

答案 3 :(得分:0)

执行此操作的最一般和最简洁的方法是使用Scalaz的半群类型类。这样,您不仅限于List[Option[Int]],而是可以将相同的功能应用于List[Int]

import scalaz._
import Scalaz._

object S {
  def double[A:Semigroup](l:List[A]) = l.map(x => x |+| x)
  def sum[A:Semigroup](l:List[A]) = l.reduce(_ |+| _)

  def main(a:Array[String]) {
    val l = List(Some(1), None, Some(2))
    val l2 = List(1,2)
    println(double(l))
    println(sum(l))
    println(double(l2))
    println(sum(l2))
  }

}

打印

List(Some(2), None, Some(4))
Some(3)
List(2, 4)
3

答案 4 :(得分:0)

我不确定你想要实现的是什么,但这似乎不是正确的做法。如果您需要确定“列表”中是否存在某个值,那么Set可以更好地满足您的需求:

scala> val s = Set(4,8)
s: scala.collection.immutable.Set[Int] = Set(4, 8)

scala> s(4)
res0: Boolean = true

scala> s(5)
res1: Boolean = false

scala> s map (_ * 2)
res2: scala.collection.immutable.Set[Int] = Set(8, 16)

scala> s reduceLeft((a,b) => a+b)
res3: Int = 12

甚至更容易:

scala> s sum
res4: Int = 12

如果你需要更复杂的东西,并且列表中元素的索引很重要,你可以使用Map,其中键模拟索引,缺失值可以映射到某个默认值:< / p>

scala> val m = Map(1 -> 4, 2 -> 8) withDefault(n => 0)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 2 -> 8)

scala> m(1)
res5: Int = 4

scala> m(3)
res6: Int = 0

scala> m map {case (k,v) => (k,2*v)}
res7: scala.collection.immutable.Map[Int,Int] = Map(1 -> 8, 2 -> 16)

scala> m.foldLeft(0){case (sum,(_,v)) => sum+v}
res8: Int = 12

再次,不确定你的需求是什么,但感觉你走错了方向...... Option是我在使用之前会三思的类型。问自己是否真的有必要。可能有一些解决方案能够以更优雅的方式实现您的目标。