避免在警卫中重复计算

时间:2016-06-28 14:58:07

标签: scala

以下是代码:

import java.util.{Calendar, Date, GregorianCalendar}

import com.mongodb.casbah.Imports._
import com.mongodb.casbah.commons.conversions.scala._
case class Quota(date: Date, used: Int)
object MongoDateDemo extends App {
  val client = InsertUsers.getClient
  val db = client("github")
  val quota = db("quota")
  val rand = scala.util.Random
//  quota.drop()
//  (1 to 100).foreach { _ =>
//    quota += DBObject("date" -> new Date(), "used" -> rand.nextInt(10))
//    Thread.sleep(1000)
//  }
  val minuteInMilliseconds = 60 * 1000
  def thresholdDate(minute: Int) = new Date(new Date() .getTime - minuteInMilliseconds * minute) // since a minute ago
  val fields = DBObject("_id" -> 0, "used" -> 1)
  val x = quota.find("date" $gte thresholdDate(28), fields).collect {
    case x if x.getAs[Int]("used").isDefined => x.getAs[Int]("used").get
  }
  println(x.toList.sum)
//  val y = x.map {
//    case dbo: DBObject => Quota(dbo.getAs[Date]("date").getOrElse(new Date(0)), dbo.getAs[Int]("used").getOrElse(0))
//  }
}

它正在从一个集合中读取文档,并过滤掉那些没有使用过的文档"定义,然后总结数字。

x.getAs[Int]("used")部分是重复计算,我该如何避免呢?

3 个答案:

答案 0 :(得分:3)

Scala程序员并不多,但是flatMap的用途是什么?

quota
  .find("date" $gte thresholdDate(38), fields)
  .flatMap(_.getAs[Int]("used").toList)

答案 1 :(得分:0)

由于这是不可避免的,我必须分两步完成,映射到Option然后收集。我使用了view方法,因此集合不会遍历两次:

import java.util.{Calendar, Date, GregorianCalendar}

import com.mongodb.casbah.Imports._
import com.mongodb.casbah.commons.conversions.scala._
case class Quota(date: Date, used: Int)
object MongoDateDemo extends App {
  val client = InsertUsers.getClient
  val db = client("github")
  val quota = db("quota")
  val rand = scala.util.Random
//  quota.drop()
//  (1 to 100).foreach { _ =>
//    quota += DBObject("date" -> new Date(), "used" -> rand.nextInt(10))
//    Thread.sleep(1000)
//  }
  val minuteInMilliseconds = 60 * 1000
  def thresholdDate(minute: Int) = new Date(new Date() .getTime - minuteInMilliseconds * minute) // since a minute ago
  val fields = DBObject("_id" -> 0, "used" -> 1)
  val usedNumbers = quota.find("date" $gte thresholdDate(38), fields).toList.view.map {
    _.getAs[Int]("used")
  }.collect {
    case Some(i) => i
  }.force
  println(usedNumbers.sum)
//  val y = x.map {
//    case dbo: DBObject => Quota(dbo.getAs[Date]("date").getOrElse(new Date(0)), dbo.getAs[Int]("used").getOrElse(0))
//  }
}

答案 2 :(得分:0)

假设getAs返回一个选项,这应该可以达到你想要的效果:

val x = quota.find("date" $gte thresholdDate(28), fields).flatMap { _.getAs[Int]("used") }

这类似于这样做:

scala> List(Some(1), Some(2), None, Some(4)).flatMap(x => x)
res: List[Int] = List(1, 2, 4)

或者这个:

scala> (1 to 20).flatMap(x => if(x%2 == 0) Some(x) else None)
res: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)