如何使用Go的text/template包返回数组中的唯一元素?

huangapple go评论69阅读模式
英文:

How to return unique elements in an array using Go's text/template package?

问题

我是你的中文翻译助手,以下是你要翻译的内容:

我刚开始学习Go语言,我正在努力寻找一种从Go模板语言中返回数组中唯一变量的方法。这是为了配置一些软件,我无法访问源代码,只能更改模板。

我在Go Playground上创建了一个示例:

https://play.golang.org/

package main

import "os"
import "text/template"

func main() {

      var arr [10]string
      arr[0]="mice"
      arr[1]="mice"
      arr[2]="mice"
      arr[3]="mice"
      arr[4]="mice"
      arr[5]="mice"
      arr[6]="mice"
      arr[7]="toad"
      arr[8]="toad"
      arr[9]="mice"

      tmpl, err := template.New("test").Parse("{{range $index, $thing := $}}The thing is: {{$thing}}\n{{end}}")
      if err != nil { panic(err) }
      err = tmpl.Execute(os.Stdout, arr)
      if err != nil { panic(err) }

}

目前这个代码返回:

The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: toad
The thing is: toad
The thing is: mice

我想做的是创建一个模板,从输入的数组中过滤掉重复的值,只返回:

The thing is: mice
The thing is: toad

我真的很困惑,因为我几乎不了解Go语言,也很难在文档中找到任何数组操作方法。有人有什么建议吗?

补充说明

抱歉没有表达清楚,我在上班的路上在公交车上写了这个问题。

我无法在模板之外访问任何Go代码。我有一个可以编辑的模板,在该模板中,我有一个可能包含多个值的数组,我需要打印它们一次。

我知道这不是模板的正常用法,但如果有一种"不正当"的方法可以实现这个目的,那将节省我几天的工作时间。

英文:

I am new to Go and I am struggling trying to figure out a way to return unique variables from an array in Go templating language. This is to configure some software and I do not have access to the source to change the actual program only the template.

I have knocked up an example in the Go playground:

https://play.golang.org/

package main

import "os"
import "text/template"

func main() {

      var arr [10]string
      arr[0]="mice"
      arr[1]="mice"
      arr[2]="mice"
      arr[3]="mice"
      arr[4]="mice"
      arr[5]="mice"
      arr[6]="mice"
      arr[7]="toad"
      arr[8]="toad"
      arr[9]="mice"
    
      tmpl, err := template.New("test").Parse("{{range $index, $thing := $}}The thing is: {{$thing}}\n{{end}}")
      if err != nil { panic(err) }
      err = tmpl.Execute(os.Stdout, arr)
      if err != nil { panic(err) }

}

Right now this returns:

The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: toad
The thing is: toad
The thing is: mice

What I am trying to do is craft a template that from the input array filters duplicates and only returns:

The thing is: mice
The thing is: toad

I am really stuck as I know virtually no go and struggle to find any array manipulation methods in the docs. Any one have any tips?

Addenium

Sorry for not being clear I wrote this question on the bus on the way to work.

I don't have access to any go code outside the template. I have a template I can edit and within that template I have an array that may or may not have multiple values and I need to print them once.

I appreciate this is not how templates are meant to work but if there is some dirty way to do this it would save me several days work.

答案1

得分: 5

你可以通过template.FuncMap来为模板创建自己的函数:

arr := []string{
    "mice",
    "mice",
    "mice",
    "mice",
    "mice",
    "mice",
    "mice",
    "toad",
    "toad",
    "mice",
}

customFunctions := template.FuncMap{"unique": unique}

tmpl, err := template.New("test").Funcs(customFunctions).Parse("{{range $index, $thing := unique $}}The thing is: {{$thing}}\n{{end}}")

其中unique函数定义如下:

func unique(e []string) []string {
    r := []string{}

    for _, s := range e {
        if !contains(r[:], s) {
            r = append(r, s)
        }
    }
    return r
}

func contains(e []string, c string) bool {
    for _, s := range e {
        if s == c {
            return true
        }
    }
    return false
}

输出结果为:

The thing is: mice
The thing is: toad

(使用map可能更好,但这给出了基本的思路)

话虽如此,你是否考虑在模板之外进行过滤呢?这样会更方便,然后你可以在模板中直接迭代实际的切片。

工作示例:https://play.golang.org/p/L_8t10CpHW

英文:

You can create your own functions for the template via template.FuncMap:

arr := []string{
	"mice",
	"mice",
	"mice",
	"mice",
	"mice",
	"mice",
	"mice",
	"toad",
	"toad",
	"mice",
}

customFunctions := template.FuncMap{"unique" : unique}

tmpl, err := template.New("test").Funcs(customFunctions).Parse("{{range $index, $thing := unique $}}The thing is: {{$thing}}\n{{end}}")

Where unique is defined as:

func unique(e []string) []string {
	r := []string{}

	for _, s := range e {
		if !contains(r[:], s) {
			r = append(r, s)
		}
	}
	return r
}

func contains(e []string, c string) bool {
	for _, s := range e {
		if s == c {
			return true
		}
	}
	return false
}

Output:

The thing is: mice
The thing is: toad

(It might be better to use a map .. but this gives you the basic idea)

That said - have you considered filtering this outside of the template? That would make things nicer for you.. then you can just iterate over the actual slice within the template.

Working sample: https://play.golang.org/p/L_8t10CpHW

答案2

得分: 0

模板可以访问特定的自定义函数http://golang.org/pkg/text/template/#FuncMap。这允许在模板内部调用自己的逻辑。

文档中有一个详细的示例,我就不在这里重复了。关键的一行是设置一个函数映射并将其提供给模板:

tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)

然后可以在模板内部访问它:

{{myCustomFunction .}}

既然现在已经确定需要更多的Go代码来实现映射函数,我想分享一个可能完成任务的想法。如果你能控制无法修改的"go"程序所运行的模板,那么你可以进行多次处理。我还假设你在Linux上。类似这样:

goexe 'first template'    // 这将写入'text file'
cat textfile | sort | uniq > 'text file'
goexe 'second template'   // 你想要的输出

请注意,这只是一个思路,具体实现可能需要根据你的具体情况进行调整。

英文:

The template can acces a particular custom function http://golang.org/pkg/text/template/#FuncMap. This allows your own logic to be called from within the template.

There is a comprehensive example in the docs which I wont repeat here. The key line is setting up a funcion Map and providing this to the template:

 tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)

Then can be accessed within the template.

 {{myCustomFuction .}}

Since now it is established that it will take more go code in the form of a mapped function to achieve, I thought I would share a thought that might get the job done. If you have control of which template that the 'go' program you are not able to modify runs, then you could make several passes. I am also assuming you are on linux. Something like this:

goexe 'first template'    // this writes to 'text file'
cat textfile | sort | uniq > 'text file'
goexe 'second template'   // your desired output

huangapple
  • 本文由 发表于 2014年11月12日 05:29:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/26874933.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定