【问题标题】:Get index of element from array / slice or key of value from map in Go?从Go中的数组/切片或值的键中获取元素的索引?
【发布时间】:2015-11-04 09:21:20
【问题描述】:

我有一个字符串的枚举列表(它是常量,例如国家列表),我希望能够在提供枚举的 int 值时获取该字符串,反之亦然提供字符串时枚举的 int 值。这是为了在两者之间转换数据库事务。

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

这对于像 python 这样的语言来说很容易,只需执行类似 MyData[1] 来获取“string2”和 MyData.index(“string2”) 来获取 1。

一些可能的解决方案是

  • 编写我自己的函数,通过遍历数组/切片来获取索引
  • 对数组/切片进行排序并使用搜索函数返回索引(尽管这不允许未排序的序列,这是我更喜欢的)
  • 维护相互镜像的映射和数组,容易出错。

说到地图,可以访问特定值的键吗?那么我可以简单地拥有如下的地图,并且能够在提供 int 值时获取字符串键。

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

更新:在我接受我的回答之前,我想更彻底地解释这个问题,我知道这一定是相当普遍的。我基本上有一组常量字符串(例如国家列表),每个字符串都有一个相关的整数值。在我的数据库中,我只是存储整数以节省空间,因为有数百万个条目。但是当我显示来自数据库的条目时,我需要显示字符串值,以便用户可以读取它。一个简单的数组就可以做到这一点。但是,我还需要向数据库中添加条目(例如一个新人和他们的居住国家/地区),并且在这种情况下需要将表单中输入的国家字符串转换为该整数值。同样,这只是一个示例用例,但目标保持不变。我需要一个可以在字符串值和枚举 int 值之间双向转换的表。 最明显的事情是维护一个数组(用于 int 到字符串的转换)和一个映射(用于字符串到 int 翻译)。我不想手动维护这两个变量,因为这很容易出错。所以我下面的解决方案是只维护一个数组,并让构造函数方法在程序第一次运行时在运行时自动构建映射。这样做的好处是当我根据字符串获取整数值时不需要遍历整个数组(这是另一个建议的解决方案)。

【问题讨论】:

  • 很久以前的这个帖子似乎就是你要找的东西。 stackoverflow.com/questions/8307478/…
  • 我想我实际上可以使用第三个选项来维护一个 map[string]int,并在运行时创建镜像的 []string 数组,这样我就不会那么容易出现镜像错误手动设置它们,并且它比遍历数组以确定索引更高效。

标签: go


【解决方案1】:

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

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

或定长数组

data := [3] {"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[:]))

【讨论】:

  • (int) 括号不是必需的。 Webstorm 用“多余的括号”发出警告
【解决方案2】:

这是我之前提到的一个解决方案,它适用于静态切片(这是我的用例)。每次我想要一个值的索引时迭代切片会增加不必要的延迟,特别是因为我的数据在运行时是静态的。这只是创建了一个初始化切片并创建相应逆映射的结构。然后我将使用 GetKey 和 GetVal 方法通过提供 int 'value' 来获取字符串 'key',或者通过提供字符串 'key' 来获取 int 'value'。也许已经有一种方法可以在 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]
}

【讨论】:

  • 这是一个老问题,我同意作者没有要求这样的功能,但是一旦你开始删除对象,所有的索引都会打乱,你必须重新分配一切。
【解决方案3】:

在这两种情况下,您都应该只使用内置的 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    相关资源
    最近更新 更多