Get index of element from array / slice or key of value from map in Go?

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

Get index of element from array / slice or key of value from map in Go?

问题

我有一个字符串的枚举列表(这些字符串是常量,例如国家列表),我希望能够通过提供枚举的整数值来获取字符串,并且反过来,通过提供字符串来获取枚举的整数值。这是为了在数据库事务中在两者之间进行转换。

var MyData = [...]string {
  "string1", // 索引 0
  "string2", // 索引 1
  "string3", // 索引 2  
}

在像Python这样的语言中,这很容易实现,可以通过MyData[1]来获取"string2",通过MyData.index("string2")来获取1。

一些可能的解决方案包括:

  • 编写自己的函数来通过迭代数组/切片来获取索引
  • 对数组/切片进行排序,并使用搜索函数返回索引(尽管这不允许对未排序的序列进行操作,而我更喜欢这种方式)
  • 维护一个相互映射的映射和数组,但这容易出错。

**说到映射,是否可以访问特定值的键?**然后我可以简单地使用如下的映射,通过提供整数值来获取字符串键。

var MyData = map[string]int {
  "string1": 0,
  "string2": 1,
  "string3": 2,
}

**更新:在接受我的答案之前,我想更详细地解释一下问题,我知道这个问题可能相当常见。我基本上有一组字符串,它们是常量的(例如国家列表),每个字符串都有一个关联的整数值。在我的数据库中,我只是存储整数以节省空间,因为有数百万条记录。但是当我显示数据库中的条目时,我需要显示字符串值,以便用户能够阅读。对于这个目的,一个简单的数组就足够了。然而,我还需要向数据库中添加条目(例如新的人员及其居住国家),在这种情况下,我需要将从表单中输入的国家字符串转换为整数值。再次强调,这只是一个示例用例,但是目标仍然是相同的。我需要一个能够在字符串值和枚举整数值之间双向转换的表格。**最明显的做法是维护一个数组(用于整数到字符串的转换)和一个映射(用于字符串到整数的转换)。我不想手动维护这两个变量,因为容易出错。因此,我的解决方案是只维护一个数组,并在程序第一次运行时,由构造函数方法自动构建映射。这样做的好处是在根据字符串获取整数值时不需要遍历整个数组(这是另一个提出的解决方案)。

英文:

I have an enumerated list of strings (which are constant, e.g. a list of countries), that I'd like to be able to get the string when providing the enumerated int value, and vice-versa be able to get the enumerated int value when providing the string. This is in order to translate between the two for database transactions.

var MyData = [...]string {
  "string1", // index 0
  "string2", // index 1
  "string3", // index 2  
}

That's easy for a language like python, where one can just do something like MyData[1] to get "string2" and MyData.index("string2") to get 1.

A few possible solutions would be to

  • write my own function to get the index by iterating over the array / slice
  • sort the array / slice and use a search function to return index (though this doesn't allow for an unsorted sequence, which is what I'd prefer)
  • maintain a map and an array that mirror each other, which is prone to errors.

Speaking of maps, can one access the key of a particular value? Then I could simply have a map like the following, and be able to get the string key when providing the int value.

var MyData = map[string]int {
  "string1": 0,
  "string2": 1,
  "string3": 2,
}

UPDATE: Before I accept my answer, I want to explain the problem more thoroughly, which I know must be fairly common. I basically have a set of strings that are constant (such as a list of countries) each with an associated integer value. In my database I simply store the integer to conserve space, since there are millions of entries. But when I display an entry from the database I need to display the string value for it to be readable to a user. A simple array will do for that. However, I also need to add entries to the database (such as a new person and their country of residence) and in this scenario need to translate from the country string which is entered in a form to that integer value. Again, this is just an example use case, but the goal remains the same. I need a table that can translate in both directions between a string value and an enumerated int value. The most obvious thing to do is to maintain an array (for the int to string translation) and a map (for the string to int translation). I'd prefer not to manually maintain both variables, since this is prone to errors. So my solution below is to maintain just a single array, and have the constructor method automatically build the map at runtime when the program is first run. This has the advantage of not needing to iterate over the entire array when I fetch the integer value based on the string (which was the other proposed solution).

答案1

得分: 4

在这两种情况下,你应该使用内置的range函数。

for k, v := range MyData {
}


for i, v := range ThisArray {
}


for i, _ := range ThisArrayIndexOnly {
    value := ThisArrayIndexOnly[i]
}

你可以在此基础上构建辅助函数或其他任何你喜欢的东西,但是range是访问这些数据的基本机制。如果你想要一个"indexof"函数,可以这样写:

for i, v := range ArrayPassedIntoFunction {
     if v == ValuePassedIntoFunction {
          return i
     }
}
return -1

当然,要获取值,你只需使用MyArray[i],包括边界检查或其他操作。请注意,上面的伪代码是以数组的形式编写的,但几乎相同的代码也适用于映射,我通常会使用变量名k而不是i

英文:

In both cases you should just use the built in range function.

for k, v := range MyData {
}


for i, v := range ThisArray {
}


for i, _ := range ThisArrayIndexOnly {
    value := ThisArrayIndexOnly[i]
}

You can build helper functions or whatever you like on top of this but range is fundamentally the mechanism available for accessing that data. If you want an "indexof" function it would be

for i, v := range ArrayPassedIntoFunction {
     if v == ValuePassedIntoFunction {
          return i
     }
}
return -1

To get the value, you of course would just do MyArray[i] including a bounds check or whatever. Note the pseudo code above is written in a style that indicates it's an array but virtually the same code will work for a map, I would just typically use the var name k instead of i.

答案2

得分: 4

假设你想在数组数据中获取单词的索引。

data := [...]string{"one", "two", "three"}

或者是固定长度的数组

data := [3]string{"one", "two", "three"}

创建函数

func indexOf(word string, data []string) int {
    for k, v := range data {
        if word == v {
            return k
        }
    }
    return -1
}

要从上面的函数中获取值,为了匹配类型,请使用array[:]传递数组,如下所示

fmt.Println(indexOf("two", data[:]))
英文:

Assume you want getting index of word in the data of array

data := [...] {"one","two","three"}

or fixed length array

data := [3] {"one","two","three"}

create function

func indexOf(word string, data []string) (int) {
 	for k, v := range data {
		if word == v {
			return k
		}
	}
	return -1
}

to get value from function above, to match the type, pass the array with array[:] like below

fmt.Println(indexOf("two", data[:]))

答案3

得分: 3

这是我之前提到的一个解决方案,适用于静态切片(这是我的用例)。每次我想要一个值的索引时,迭代切片会增加不必要的延迟,特别是在运行时我的数据是静态的。这只是创建一个结构体,初始化切片并创建相应的反向映射。然后,我可以使用GetKey和GetVal方法,通过提供整数值获取字符串"key",或者通过提供字符串"key"获取整数值。也许在Go语言中已经有一种方法可以获取特定值的键。

type MyData struct {
    dataslice []string
    datamap map[string]int
}

func NewMyData() *MyData {
    m := new(MyData)
    m.dataslice = []string {
        "string1",
        "string2",
        "string3",
    }
    m.datamap = make(map[string]int)
    for x := range m.dataslice {
        m.datamap[m.dataslice[x]] = x
    }
    return m
}

func (m *MyData) GetKey(x int) string {
    return m.dataslice[x]
}

func (m *MyData) GetVal(x string) int {
    return m.datamap[x]
}
英文:

Here's a solution that I mentioned earlier, which works well for static slices (which is my use case). Iterating over the slice every time I want the index of a value adds unnecessary delay, especially since my data is static during runtime. This just creates a struct which initializes the slice and creates the corresponding inverse map. And then I would use the GetKey and GetVal methods to get either the string 'key' by providing the int 'value', or get the int 'value' by providing the string 'key'. Perhaps there's already a way to get the key of a particular value of a map in Go.

type MyData struct {
    dataslice []string
    datamap map[string]int
}

func NewMyData() *MyData {
    m := new(MyData)
    m.dataslice= []string {
        "string1",
        "string2",
        "string3",
    }
    m.datamap = make(map[string]int)
    for x := range m.dataslice {
        m.datamap[m.dataslice[x]] = x
    }
    return m
}

func (m *MyData) GetKey(x int) string {
    return m.dataslice[x]
}

func (m *MyData) GetVal(x string) int {
    return m.datamap[x]
}

huangapple
  • 本文由 发表于 2015年8月12日 07:47:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/31953818.html
匿名

发表评论

匿名网友

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

确定