英文:
Choose content randomly in Go templates
问题
我想根据给定的权重随机选择生成文档的一部分,类似于以下伪代码:
{{prob 50}}
这将以50%的概率出现。
{{prob 30}}
这将以30%的概率出现。
{{prob 20}}
你明白了吧。
{{endprob}}
到目前为止,我想到的最好的方法是:
{{choose . "template1" 50 "template2" 30 "template3" 20}}
其中choose
是属于FuncMap
的函数。当前模板被传递给自身,例如.T
,而templateN
是相关的模板。该函数将选择模板,在.T
中查找并使用.
进行渲染。另一个类似的选项是直接将templateN
作为.
的一部分传递。
我想知道是否有更优雅/不那么hackish的方法?我猜,在text/template
中创建自定义操作是不可能的,对吗?
英文:
I would like to choose a part of the generated document randomly based on the given weights, something like this pseudo-code:
{{prob 50}}
This will appear with probability 50%.
{{prob 30}}
This will appear with probability 30%.
{{prob 20}}
You got the idea.
{{endprob}}
The best things that has come to my mind so far is:
{{choose . "template1" 50 "template2" 30 "template3" 20}}
where choose
is my function that belongs to FuncMap
. The current template is passed to itself as e.g. .T
and templateN
are the associated templates. The function would choose the template, look it up in .T
and render with .
. Another similar option would be to pass templateN
as part of .
directly.
I wonder if there's a more elegant / less hackish way? I guess, it's not possible to create custom actions in text/template
, is it?
答案1
得分: 3
标准模板包不支持自定义操作。
您可以通过使用函数映射和内置的{{if}}
操作来实现接近您提出的{{prob}}/{{endprob}}
操作。
将权重转换为不重叠的范围[0.0,1.0)。使用在[0.0,1.0)范围内的随机数来选择一个替代项,使用模板中的if操作。
var t = template.Must(template.New("").Funcs(template.FuncMap{"rand": rand.Float64}).Parse(`
{{$r := rand}}
{{if le $r 0.5}}
This will appear with probability 50%.
{{else if le $r 0.8}}
This will appear with probability 30%.
{{else}}
You got the idea.
{{end}}`))
[kbd][playground](http://play.golang.org/p/c_4SryGkL8)[/kbd]
这是另一种允许您在模板中指定权重而不是范围的替代方法:
type randPicker struct {
n float64 // random number in [0.0,1.0)
t float64 // total of weights so far
}
func (rp *randPicker) Weight(w float64) bool {
rp.t += w
return rp.t <= rp.n
}
func newRandPicker() *randPicker {
return &randPicker{n: rand.Float64()}
}
var t = template.Must(template.New("").Funcs(template.FuncMap{"rp": newRandPicker}).Parse(`
{{$rp := rp}}
{{if rp.Weight 0.50}}
This will appear with probability 50%.
{{else if rp.Weight 0.30}}
This will appear with probability 30%.
{{else}}
You got the idea.
{{end}}`))
[kbd][playground](http://play.golang.org/p/oGbawWH4Xg)[/kbd]
<details>
<summary>英文:</summary>
The standard template packages do not support custom actions.
You can get close to your proposed `{{prob}}/{{endprob}}` action using a function map and the built-in `{{if}}` action.
Convert the weights to non-overlapping ranges in [0.0,1.0). Use a random number in [0.0,1.0) to select an alternative using an if action in the template.
var t = template.Must(template.New("").
Funcs(template.FuncMap{"rand": rand.Float64}).
Parse(`
{{$r := rand}}
{{if le $r 0.5}}
This will appear with probability 50%.
{{else if le $r 0.8}}
This will appear with probability 30%.
{{else}}
You got the idea.
{{end}}`))
<kbd>[playground](http://play.golang.org/p/c_4SryGkL8)</kbd>
Here's an alternative that allows you to specify weights in the template instead of ranges:
type randPicker struct {
n float64 // random number in [0.0,1.0)
t float64 // total of weights so far
}
func (rp *randPicker) Weight(w float64) bool {
rp.t += w
return rp.t <= rp.n
}
func newRandPicker() *randPicker {
return &randPicker{n: rand.Float64()}
}
var t = template.Must(template.New("").
Funcs(template.FuncMap{"rp": newRandPicker}).
Parse(`
{{$rp := rp}}
{{if rp.Weight 0.50}}
This will appear with probability 50%.
{{else if rp.Weight 0.30}}
This will appear with probability 30%.
{{else}}
You got the idea
{{end}}`))
<kbd>[playground](http://play.golang.org/p/oGbawWH4Xg)</kbd>
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论