Map combat in the "translate" go language

Source: Internet
Author: User
Tags comparable key string
This is a creation in Article, where the information may have evolved or changed.

In the spare time translation, the level is very poor, if has the flaw, is purely incompetent.

Original link

Http://blog.golang.org/go-maps-in-action

Map combat in the Go language

1. Introduction

A hash table is one of the most important data structures in computer science. Many hash table implementations have different characteristics, but in general they provide quick query, add and delete functions. The go language provides a built-in data type map.

2. Declaration and initialization

The declaration format for map is as follows:

Map[keytype] ValueType

The KeyType type must be comparable, and valuetype can be any type, or even another map.

The following m is a hash table with a key value of string and a value of int:

var m map[string]int

The hash table type is a reference type, and the value that the pointer or slice m points to is nil; it does not point to an initialized hash table. A nil hash table reads like an empty hash table, but trying to write data to M throws a run-time panic, so don't do that. Use built-in function make to initialize a hash table:

m = Make (Map[string]int)

The Make function requests and initializes a hash table data structure and returns a pointer to this initialized hash table. The data structure of a hash table is an implementation detail of the runtime of the go itself, and is not defined by the language itself as "the flip-flop: similar to how C + + compilers implement virtual functions." The article only cares about the use of hash tables rather than implementations.

3. Using a hash table

The hash table in Go is used in a similar way to other languages, and a statement with a key of "route" value 66 is inserted into the Hashtable:

m["route"] = 66

The statement that the query key is "route" and assigns the corresponding value to the new variable i is:

I: = m["Route"]

If the key value of the query does not exist in the hash table, it will get the value type "0" value. In M, for example, the value type is int, and the value of "0" is 0:

J: = m["root"]//j = = 0

Len is a built-in function that returns the number of data in a hash table:

N: = Len (M)

Delete is a built-in function that deletes a key value data from a hash table:

Delete (M, "route")

The delete function returns a null value and does nothing if the key value does not exist.

You can check if a key value exists by using two return values:

I, OK: = m["Route"]

In this statement, I is assigned the value of the "route" key value in the hash table. If the key value does not exist, I is assigned a value of "0" in the value type. The second return value is a Boolean type and, if true, indicates that the key value exists, otherwise it does not exist.

If you only check for the existence of a key value, the first return value uses the underscore "_":

_, OK: = m["Route"]

If you want to traverse the contents of a hash table, use the range keyword:

For key, Value: = range m {    fmt. Println ("Key:", Key, "Value:", Value)}

If you want to initialize the data, use the literal representation of the hash table:

Commits: = map[string]int{    "RSC": 3711,    "R":   2138,    "GRI": 1908,    "ADG": 912,}

The same syntax can initialize an empty hash table, and this usage achieves the same effect as make:

m = map[string]int{}

4. Using the "0" value

When querying data in a hash table, it is convenient to return a value type "0" value if the key value does not exist:

It can be convenient, that a map retrieval yields a zero value when the key was not present.

For example, a hash table of a Boolean value can be used as a set (a Boolean type of "0" value is false). The following example iterates through a node's linked list and prints their values, using a node pointer to the hash table of key to determine if there is a loop in the list:

    Type Node struct {        Next  *node        Value interface{}    }    var first *node    visited: = Make (Map[*node] BOOL) for    N: = first; n! = nil; n = n.next {        if visited[n] {            FMT. PRINTLN ("Cycle detected")            break        }        Visited[n] = True        fmt. Println (n.value)    }

Visited[n] If the expression is true, it indicates that N has been visited, and if it is false, it does not. This does not require the use of two return values to check whether n is really present in the map, and the default "0" value for us to do.

Another useful example is a sliced hash table. Adding data to an empty slice will request a new slice so append data in a tiled map takes only one row, and you don't need to check if the key exists. In the example below, the slice is used to hold the value of the person type, each man has a name field and a slice, and this example creates a hash table that associates each item with a slice of what he likes. "Made a inverted platoon?" 】

    Type person struct {        Name  string        likes []string    }    var people []*person    Likes: = Make (map[ String][]*person)    for _, p: = Range People {        for _, L: = range P.likes {            likes[l] = append (Likes[l], p)        }    }

Print a people like cheese:

    For _, P: = range likes["Cheese"] {        fmt. Println (p.name, "likes cheese.")    }

Print out the number of people who like bacon

Fmt. Println (Len (likes["Bacon"]), "people like bacon.")

Note that the range function and the Len function both treat nil slices as a zero-length slice, even if no one likes cheese or bacon, no problem.

5. Type of key

As mentioned earlier, the type of the key must be comparable. The Go language spec accurately defines this requirement, in short, the types that can be compared include: Boolean, number, string, pointer, message channel, interface type, and any struct and array containing the above types. Types that are not in this range include slices, hash tables, and functions; These types cannot be compared using "= =", nor can they be used to make hash table key values.

It is obvious that strings, integers, and other underlying types can act as keys to the hash table. The unexpected is that the struct can also be used as a key value, for example, the hash table of this hashtable can hold the number of visits to different countries.

Hits: = Make (Map[string]map[string]int)

This is a hash table with a key string and a value of string to int. Each key value of the outermost table is the path to the internal Hashtable, and the key value of each nested hash table is a two-letter country code. This expression gives the number of times an Australian person accesses a document page.

N: = hits["/doc/" ["Au"]

Unfortunately, this method is cumbersome when adding data, and for each key, it is necessary to determine whether a nested map exists and, if necessary, to create:

Func Add (M map[string]map[string]int, path, country string) {    mm, OK: = M[path]    if!ok {        mm = make (map[string] int)        M[path] = mm    }    Mm[country]++}add (hits, "/doc/", "au")

On the other hand, using structs as a hash table of keys can relieve this complexity:

Type Key struct {    Path, country string}hits: = Make (Map[key]int)

When a Vietnamese visit the homepage, one line can be done:

hits[key{"/", "VN"}]++

See how many Swiss people see the Spec page statement is also simple:

N: = hits[key{"/ref/spec", "ch"}]

6. Concurrency

The hash table is not secure in scenarios where concurrency is a scenario: the consequences of reading and writing a hash table are uncertain. If you need to use Goroutines to read and write to a hash table at the same time, access to the hash table needs to be coordinated by some sort of synchronization mechanism. One common way is to use sync. Rwmutex.

This statement declares a counter variable, which contains a map and sync. Anonymous structure of the Rwmutex.

var counter = struct{    sync. Rwmutex    m Map[string]int}{m:make (Map[string]int)}

Before reading counter, get read lock:

Counter. Rlock () N: = counter.m["Some_key"]counter. Runlock () fmt. Println ("Some_key:", N)

Get write lock before writing counter

Counter. Lock () counter.m["Some_key"]++counter. Unlock ()

7. Traversal Order

When using the range loop to traverse a hash table, the traversal order is not guaranteed to be stable. Because the GO1 version randomize the convenience order of the map, if the program relies on a stable convenience order in the previous implementation. "The Flip Note: Do not know how to translate "If you need a stable traversal order, you must maintain a separate data structure to guarantee this order." The following example uses a separate sort slice to print a map[int] string data in the order of the key values:

Import "Sort" var m map[int]stringvar keys []intfor k: = range m {    keys = append (keys, k)}sort. Ints (keys) for _, K: = Range keys {    fmt. Println ("Key:", K, "Value:", M[k])}

by Andrew Gerrand

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.