Scala:return 一个有机会的值?
Scala: return a value with a chance?
我想对一个函数建模,该函数将 return 一组具有加权概率的值。像这样:
25% => return "a"
25% => return "b"
50% => return "c"
到目前为止我看到的大多数文档都相当沉重,并且在没有示例的情况下快速深入到科学深度,因此问题是:
实现此目标的最简单方法是什么?
编辑:我正在使用 Gatling DSL 编写带有加权操作的负载测试。内置的加权分布有一个限制(不会在循环中工作),我想通过自己的实现来避免。该代码段如下所示:
override def scenarioBuilder = scenario(getClass.getSimpleName)
.exec(Account.create)
.exec(Account.login)
.exec(Account.activate)
.exec(Loop.create)
.forever(getAction)
def getAction = {
// Here is where I lost my wits
// 27.6% => Log.putEvents
// 18.2% => Log.putBinary
// 17.1% => Loop.list
// 14.8% => Key.listIncomingRequests
// rest => Account.get
}
这是根据概率选择的通用函数的最短版本:
val probabilityMap = List(0.25 -> "a", 0.25 -> "b")
val otherwise = "c"
def getWithProbability[T](probs: List[(Double, T)], otherwise: T): T = {
// some input validations:
assert(probs.map(_._1).sum <= 1.0)
assert(probs.map(_._1).forall(_ > 0))
// get random in (0, 1) range
val rand = Random.nextDouble()
// choose by probability:
probs.foldLeft((rand, otherwise)) {
case ((r, _), (prob, value)) if prob > r => (1.0, value)
case ((r, result), (prob, _)) => (r-prob, result)
}._2
}
foldLeft
不断推进概率,直到找到 r
更小的概率;如果我们还没有找到它,我们将进入下一个概率 r-prob
到 "remove" 我们已经涵盖的范围的一部分。
EDIT:等效但可能更易于阅读的版本可以使用 scanLeft
在 [=28 之前创建 累积 范围=]对于rand
已经落地的范围:
def getWithProbability[T](probs: List[(Double, T)], otherwise: T): T = {
// same validations..
// get random in (0, 1) range
val rand = Random.nextDouble()
// create cumulative values, in this case (0.25, a), (0,5, b)
val ranges = probs.tail.scanLeft(probs.head) {
case ((prob1, _), (prob2, value)) => (prob1+prob2, value)
}
ranges.dropWhile(_._1 < rand).map(_._2).headOption.getOrElse(otherwise)
}
那里,干净且准备就绪:
randomSwitchOrElse(
27.6 -> exec(Log.putEvents),
18.2 -> exec(Log.putBinary))
我想对一个函数建模,该函数将 return 一组具有加权概率的值。像这样:
25% => return "a"
25% => return "b"
50% => return "c"
到目前为止我看到的大多数文档都相当沉重,并且在没有示例的情况下快速深入到科学深度,因此问题是: 实现此目标的最简单方法是什么?
编辑:我正在使用 Gatling DSL 编写带有加权操作的负载测试。内置的加权分布有一个限制(不会在循环中工作),我想通过自己的实现来避免。该代码段如下所示:
override def scenarioBuilder = scenario(getClass.getSimpleName)
.exec(Account.create)
.exec(Account.login)
.exec(Account.activate)
.exec(Loop.create)
.forever(getAction)
def getAction = {
// Here is where I lost my wits
// 27.6% => Log.putEvents
// 18.2% => Log.putBinary
// 17.1% => Loop.list
// 14.8% => Key.listIncomingRequests
// rest => Account.get
}
这是根据概率选择的通用函数的最短版本:
val probabilityMap = List(0.25 -> "a", 0.25 -> "b")
val otherwise = "c"
def getWithProbability[T](probs: List[(Double, T)], otherwise: T): T = {
// some input validations:
assert(probs.map(_._1).sum <= 1.0)
assert(probs.map(_._1).forall(_ > 0))
// get random in (0, 1) range
val rand = Random.nextDouble()
// choose by probability:
probs.foldLeft((rand, otherwise)) {
case ((r, _), (prob, value)) if prob > r => (1.0, value)
case ((r, result), (prob, _)) => (r-prob, result)
}._2
}
foldLeft
不断推进概率,直到找到 r
更小的概率;如果我们还没有找到它,我们将进入下一个概率 r-prob
到 "remove" 我们已经涵盖的范围的一部分。
EDIT:等效但可能更易于阅读的版本可以使用 scanLeft
在 [=28 之前创建 累积 范围=]对于rand
已经落地的范围:
def getWithProbability[T](probs: List[(Double, T)], otherwise: T): T = {
// same validations..
// get random in (0, 1) range
val rand = Random.nextDouble()
// create cumulative values, in this case (0.25, a), (0,5, b)
val ranges = probs.tail.scanLeft(probs.head) {
case ((prob1, _), (prob2, value)) => (prob1+prob2, value)
}
ranges.dropWhile(_._1 < rand).map(_._2).headOption.getOrElse(otherwise)
}
那里,干净且准备就绪:
randomSwitchOrElse(
27.6 -> exec(Log.putEvents),
18.2 -> exec(Log.putBinary))