views:

122

answers:

3

I'm looking for a go language capability similar to the "dictionary" in python to facilitate the conversion of some python code.

EDIT: Maps worked quite well for this de-dupe application. I was able to condense 1.3e6 duplicated items down to 2.5e5 unique items using a map with a 16 byte string index in just a few seconds. The map-related code was simple so I've included it below. Worth noting that pre-allocation of map with 1.3e6 elements sped it up by only a few percent:

var m = make(map[string]int, 1300000) // map with initial space for 1.3e6 elements

ct, ok := m[ax_hash]
if ok {
    m[ax_hash] = ct + 1
} else {
    m[ax_hash] = 1
}
A: 

You're probably looking for a map.

Jonathan Leffler
+3  A: 

The map type. http://golang.org/doc/effective_go.html#maps

There is some difference from python in that the keys have to be typed, so you can't mix numeric and string keys (for some reason I forgot you can), but they're pretty easy to use.

dict := make(map[string]string)
dict["user"] = "so_user"
dict["pass"] = "l33t_pass1"
cthom06
You can make a map[string]interface{} to contain mixed types if you don't mind type assertions, type switches, or possibly even reflection to get the values out again.
Evan Shaw
All keys will be string values so I think this will work just fine
Hotei
@Chickencha yah I was just referring to the type of keys. I use map[string]interface{} quite a bit
cthom06
@chthom06 Even map[interface{}]interface{} is allowed, although I think structs or slices as keys might cause runtime panics, since they can't be compared.
Evan Shaw
@Chickencha For some reason I had it in my head that map[interface{}] only worked with pointers, but it definitely works with strings and numbers. You're right though, structs and slices are a no-go.
cthom06
+5  A: 

To expand a little on answers already given:

A Go map is a typed hash map data structure. A map's type signature is of the form map[keyType]valueType where keyType and valueType are the types of the keys and values respectively.

To initialize a map, you must use the make function:

m := make(map[string]int)

An uninitialized map is equal to nil, and if read from or written a panic will occur at runtime.

The syntax for storing values is much the same as doing so with arrays or slices:

m["Alice"] = 21
m["Bob"] = 17

Similarly, retrieving values from a map is done like so:

a := m["Alice"]
b := m["Bob"]

You can use the range keyword to iterate over a map with a for loop:

for k, v := range m {
    fmt.Println(k, v)
}

This code will print:

Alice 21
Bob 17

Retrieving a value for a key that is not in the map will return the value type's zero value:

c := m["Charlie"]
// c == 0

By reading multiple values from a map, you can test for a key's presence. The second value will be a boolean indicating the key's presence:

a, ok := m["Alice"]
// a == 21, ok == true
c, ok := m["Charlie"]
// c == 0, ok == false

To remove a key/value entry from a map, you flip it around and assign false as the second value:

m["Bob"] = 0, false
b, ok := m["Bob"]
// b == 0, ok == false

You can store arbitrary types in a map by using the empty interface type interface{}:

n := make(map[string]interface{})
n["One"] = 1
n["Two"] = "Two"

The only proviso is that when retrieving those values you must perform a type assertion to use them in their original form:

a := n["One"].(int)
b := n["Two"].(string)

You can use a type switch to determine the types of the values you're pulling out, and deal with them appropriately:

for k, v := range n {
    switch u := v.(type) {
        case int:
            fmt.Printf("Key %q is an int with the value %v.\n", k, u)
        case string:
            fmt.Printf("Key %q is a string with the value %q.\n", k, u)
    }
}

Inside each of those case blocks, u will be of the type specified in the case statement; no explicit type assertion is necessary.

This code will print:

Key "One" is an int with the value 1.
Key "Two" is a string with the value "Two".

The key can be of any type for which the equality operator is defined, such as integers, floats, strings, and pointers. Interface types can also be used, as long as the underlying type supports equality. (Structs, arrays and slices cannot be used as map keys, because equality is not defined on those types.)

For example, the map o can take keys of any of the above types:

o := make(map[interface{}]int)
o[1] = 1
o["Two"] = 2

And that's maps in a nutshell.

Andrew Gerrand
More like maps and type switches in a nutshell, with a dash of the empty inerface{}. Excellent answer.
cthom06