使用`map`函数按特定顺序插入对象。

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

Insert objects in specific order with map

问题

我有一个使用案例,其中对象的顺序需要按特定顺序排列。当前的实现是使用map,我找到了许多帖子和文章,其中指出map是一个无序列表。我找到的所有解决方案都是将键设置为整数,并使用sort.Ints(keys)按键排序。

在代码中,我使用一个yaml模板来实例化一个字典对,然后将其传递给ProcessFruits函数进行逻辑处理。

我该如何获得期望的结果(见下文),即始终将fruits.yml.tmpl中列表顶部的对象放在第一位?

这是我代码的简化版本:

//文件名:fruits.yml.tmpl

fruits: {{ $fruits := processFruits
  "oranges"    true
  "bananas"    false
  "apples"    true
  }}
  {{ $fruits }}
//文件名:fruits.go

func ProcessFruits(fruits map[string]interface{}) (interface{}) {
  keys := make([]string, len(fruits))

  i := 0
  for fruit := range fruits {
    keys[i] = fruit
    i++
  }

  sort.Strings(keys)
  fmt.Println(keys)
}
//将fruits.yml.tmpl连接到ProcessFruits函数
tmpl, err := template.New(t).Funcs(template.FuncMap(map[string]interface{}{
    "processFruits":        ProcessFruits,
})).Funcs(sprig.TxtFuncMap())

实际结果:

[apples:true bananas:false oranges:true]

期望结果:

[oranges:true bananas:false apples:true]

Go Playground

https://go.dev/play/p/hK2AdRVsZXJ

英文:

I have a use case where the order of objects needs to be in a specific order. The current implementation is done with using map and I've found numerous posts and articles where it states that map are an unordered list. All of the solutions that I found are those where they've made the keys as integers and they've used sort.Ints(keys) to sort by keys.

In the code, I'm using a yaml template to instantiate a dictionary pair, then passing it into the ProcessFruits function where it does the logic.

How would I go about getting the desired result (see below) where the object from the top of the list in fruits.yml.tmpl will always be first?

Here's a simplified version of my code:

//Filename: fruits.yml.tmpl

fruits: {{ $fruits := processFruits
  "oranges"    true
  "bananas"    false
  "apples"    true
  }}
  {{ $fruits }}
//Filename: fruits.go

func ProcessFruits(fruits map[string]interface{}) (interface{}) {
  keys := make([]string, len(fruits))

  i := 0
  for fruit := range fruits {
    keys[i] = fruit
    i++
  }

  sort.Strings(keys)
  fmt.Println(keys)
}
// Connect fruits.yml.tmpl to the ProcessFruits function
tmpl, err := template.New(t).Funcs(template.FuncMap(map[string]interface{}{
    "processFruits":        ProcessFruits,
})).Funcs(sprig.TxtFuncMap())

Actual Results:

[apples:true bananas:false oranges:true]

Desired Results:

[oranges:true bananas:false apples:true]

Go Playground

https://go.dev/play/p/hK2AdRVsZXJ

答案1

得分: 0

你错过了使用sort.Reverse()和sort.StringSlice()的用法。

func main() {
    keys := []string{"bananas", "apples", "oranges"}
    sort.Sort(sort.Reverse(sort.StringSlice(keys)))
    fmt.Println(keys)
}

你可以在这个链接中查看代码示例:https://go.dev/play/p/n08S7xtbeij

更多信息请参考:https://pkg.go.dev/sort#example-Reverse

英文:

You are missing the usage of sort.Reverse() and sort.StringSlice()

func main() {
	keys := []string{"bananas", "apples", "oranges"}
	sort.Sort(sort.Reverse(sort.StringSlice(keys)))
	fmt.Println(keys)
}

https://go.dev/play/p/n08S7xtbeij

See: https://pkg.go.dev/sort#example-Reverse

答案2

得分: 0

参数作为切片传递。将每隔一个参数作为字符串收集起来并打印:

func ProcessFruits(args ...interface{}) interface{} {
    var fruits []string
    for i, arg := range args {
        if i%2 == 0 {
            fruits = append(fruits, arg.(string))
        }
    }
    fmt.Println(fruits)
    return nil
}
英文:

The arguments are passed as a slice. Collect every other argument as a string and print:

func ProcessFruits(args ...interface{}) interface{} {
    var fruits []string
    for i, arg := range args {
        if i%2 == 0 {
            fruits = append(fruits, arg.(string))
        }
    }
    fmt.Println(fruits)
    return nil
}

答案3

得分: 0

不是最漂亮的解决方案,但我想我已经找到了一个解决我的问题的可行代码。我所做的是创建另一个字典来跟踪“水果”的顺序,然后使用嵌套的for循环将这两个字典合并在一起,并将结果输出到一个切片中。

这是我的代码:

package main

import (
	"fmt"
	"sort"
)

func ProcessFruits(fruits map[string]interface{}, counts map[int]string) {
	keys := make([]string, len(fruits))
	var foo []string
	var baz []int

	for k := range fruits {
		foo = append(foo, k)
	}
	for _, k := range foo {
		fmt.Println("键-字符串:", k, "值-布尔:", fruits[k])
	}

	fmt.Println("==========================")

	// 遍历计数(键是整数)
	for l := range counts {
		baz = append(baz, l)
	}
	sort.Ints(baz)
	for _, l := range baz {
		fmt.Println("键-整数:", l, "值-字符串:", counts[l])
	}

	fmt.Println("==========================")
	// 将具有排序后的整数键的列表与包含真/假的其他列表相关联

	i := 0
	for _, m := range baz {
		for _, n := range foo {
			//fmt.Println("键-整数:", m, "值-字符串:", counts[m])
			//fmt.Println("键-字符串:", n, "值-布尔:", fruits[n])

			if counts[m] == n {
				keys[i] = n
				i++
				//fmt.Println(i)
			}

		}
	}

	// 所需结果现在在切片keys中。
	fmt.Println(keys)

}

func main() {

	var m = map[string]interface{}{
		"oranges": true,
		"bananas": false,
		"apples":  true,
	}

	var n = map[int]string{
		0: "oranges",
		1: "bananas",
		2: "apples",
	}

	ProcessFruits(m, n)

}

如果有更好的解决方案,我会很好奇知道。

英文:

Not the prettiest solution, but I think I've figured out a working code to my problem. What I've done was creating another dictionary that will keep track of the order of the "fruits", then combining the two dictionary together with a nested for loop and output the result to a slice.

Here's my code:

package main

import (
	"fmt"
	"sort"
)

func ProcessFruits(fruits map[string]interface{}, counts map[int]string) {
	keys := make([]string, len(fruits))
	var foo []string
	var baz []int

	for k := range fruits {
		foo = append(foo, k)
	}
	for _, k := range foo {
		fmt.Println("Key-string:", k, "Value-bool:", fruits[k])
	}

	fmt.Println("==========================")

	// Iterate over counts (keys are ints)
	for l := range counts {
		baz = append(baz, l)
	}
	sort.Ints(baz)
	for _, l := range baz {
		fmt.Println("Key-int:", l, "Value-string:", counts[l])
	}

	fmt.Println("==========================")
	// Correlate list with sorted integer keys with the other list that contains true/false

	i := 0
	for _, m := range baz {
		for _, n := range foo {
			//fmt.Println("Key-int:", m, "Value-string:", counts[m])
			//fmt.Println("Key-string:", n, "Value-bool:", fruits[n])

			if counts[m] == n {
				keys[i] = n
				i++
				//fmt.Println(i)
			}

		}
	}

	// Desired results is now in the slice, keys.
	fmt.Println(keys)

}

func main() {

	var m = map[string]interface{}{
		"oranges": true,
		"bananas": false,
		"apples":  true,
	}

	var n = map[int]string{
		0: "oranges",
		1: "bananas",
		2: "apples",
	}

	ProcessFruits(m, n)

}

If anyone has a better solution, then I'd be curious to know.

huangapple
  • 本文由 发表于 2022年2月24日 06:06:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/71244599.html
匿名

发表评论

匿名网友

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

确定