我正在尝试对可能包含缺失值的列表进行一些算术运算。 到目前为止,我用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)
然而,这看起来比它需要的更复杂,所以我想知道我是否遗漏了一些东西。
另外,我无法弄清楚如何写总和。我想应该可以使用(大)减少表达式...
所以,我想知道是否:
mylist.map(_.map(_*2))
是映射的最佳方式答案 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
。
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
是我在使用之前会三思的类型。问自己是否真的有必要。可能有一些解决方案能够以更优雅的方式实现您的目标。