++ operator for map key loop in go - go

I am following the Go tutorial here https://tour.golang.org/moretypes/23 and have modified the exercise a little bit to try to dig deeper.
package main
import (
"fmt"
"strings"
)
func WordCount(s string) map[string]int {
m := make(map[string]int)
x := strings.Fields(s)
for _, e := range x {
m[e]++
}
return m
}
func main() {
phrase := "The quick brown fox"
fmt.Println(WordCount(phrase), "length:", len(WordCount(phrase)))
}
What doesn't make sense to me is how the ++ operator works in this context when adding new elements to the map.
Definition of ++ operator: Increment operator. It increases the integer value by one.
In this context, the ++ operator increasing the integer value of the LENGTH of the map and then adding the e element to the new map length?

The default value of int values in a map is 0. So, when you iterate through x and call m[e]++, the expanded version would be
m[e] = m[e] + 1
In other words:
m[e] = 0 + 1
Of course, if a field repeats, it will already be in the map (with some value > 0).
When you check the length of the map after the loop, it gives the number of unique fields in the string.

Related

Why do maps in Go initially have empty values depending on size of the map?

Hoping to understand maps in Go better.
Given this code:
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m []map[string]Vertex
var m1 map[string]Vertex
func main() {
m = make([]map[string]Vertex, 3)
m1 = make(map[string]Vertex)
m1["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
m = append(m, m1)
fmt.Println(m)
fmt.Println(len(m))
fmt.Println(m[3]["Bell Labs"])
}
I get an output of
[map[] map[] map[] map[Bell Labs:{40.68433 -74.39967}]]
4
{40.68433 -74.39967}
Why is it that the first 3 elements in the array are empty/null maps, shouldn't it print out [map[Bell Labs:{40.68433 -74.39967}]] instead?
Why is it that the first 3 elements in the array are empty/null maps?
The Go Programming Language Specification
Making slices, maps and channels
The built-in function make takes a type T, which must be a slice, map
or channel type, optionally followed by a type-specific list of
expressions. It returns a value of type T (not *T). The memory is
initialized as described in the section on initial values.
Call Type T Result
make(T, n) slice slice of type T with length n and capacity n
make(T, n, m) slice slice of type T with length n and capacity m
The slice m of map
m = make([]map[string]Vertex, 3)
is equivalent to
m = make([]map[string]Vertex, 3, 3)
it should be
m = make([]map[string]Vertex, 0, 3)
For example,
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m []map[string]Vertex
var m1 map[string]Vertex
func main() {
m = make([]map[string]Vertex, 0, 3)
fmt.Println(len(m), cap(m))
m1 = make(map[string]Vertex)
m1["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
m = append(m, m1)
fmt.Println(m)
fmt.Println(len(m), cap(m))
fmt.Println(m[0]["Bell Labs"])
}
Playground: https://play.golang.org/p/i9f0rrCrtY_5
Output:
0 3
[map[Bell Labs:{40.68433 -74.39967}]]
1 3
{40.68433 -74.39967}

A tuple assignment in Go

From spec:
A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right-hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion. The number of operands on the left-hand side must match the number of values. For instance, if f is a function returning two values, x, y = f() assigns the first value to x and the second to y. In the second form, the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left: one, two, three = '一', '二', '三'
The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in the left-to-right order.
Using this code ( i, n = i+2, n-1 inside for loop) :
package main
import (
"fmt"
"math"
)
func main() {
p := &Prime{}
p.Generate(1000000)
fmt.Println(p.Last()) // 15485863
}
func (p *Prime) Generate(n uint) {
p.Primes = make([]uint64, 1, n)
p.Primes[0] = 2
next:
for i := uint64(3); n > 1; i, n = i+2, n-1 {
q := uint64(math.Sqrt(float64(i)))
for _, v := range p.Primes[1:] {
if v > q {
break
}
if i%v == 0 {
continue next
}
}
p.Primes = append(p.Primes, i)
// n--
}
}
type Prime struct {
Primes []uint64
}
func (p *Prime) Last() uint64 {
return p.Primes[len(p.Primes)-1]
}
Output is:
1999993
This is not a correct result.
And this code:
func (p *Prime) Generate(n uint) {
p.Primes = make([]uint64, 1, n)
p.Primes[0] = 2
next:
for i := uint64(3); n > 1; i += 2 {
q := uint64(math.Sqrt(float64(i)))
for _, v := range p.Primes[1:] {
if v > q {
break
}
if i%v == 0 {
continue next
}
}
p.Primes = append(p.Primes, i)
n--
}
}
The output is correct:
15485863
go version go1.11.5 linux/amd64
Am I missing something on tuple Assignments in Go?
Thanks in advance.
Nope, it is not tuple assignment that gives wrong result.
There is a subtle difference between the two code, which causes the bug. In the playgound code, i,n = i+2,n-1 makes n = n-1 runs everytimes the loop is iterated, while the github code only runs n = n-1 when i is a prime (it skips n-- if continue next runs).

How to create a 2D array based on the length passed to an array

func matrix(n int) {
var result [n][n]int //Does not work
fmt.Println(result)
}
How to create a 2D array based on the length passed to an array; n is the length of the array.
The Go Programming Language Specification
Array types
An array is a numbered sequence of elements of a single type, called
the element type. The number of elements is called the length and is
never negative.
ArrayType = "[" ArrayLength "]" ElementType .
ArrayLength = Expression .
ElementType = Type .
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int. The length
of array a can be discovered using the built-in function len. The
elements can be addressed by integer indices 0 through len(a)-1. Array
types are always one-dimensional but may be composed to form
multi-dimensional types.
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int.
The size of an array is fixed at compile-time.
Use a slice instead.
For example,
package main
import "fmt"
func matrix(n int) [][]int {
m := make([][]int, n)
for i := range m {
m[i] = make([]int, n)
}
return m
}
func main() {
fmt.Println(matrix(3))
}
Playground: https://play.golang.org/p/D1MHmm5KCht
Output:
[[0 0 0] [0 0 0] [0 0 0]]
You have to allocate the further dimensions individually, like so:
func matrix(n int) {
var result = make([][]int, n)
for i := range result {
result[i] = make([]int, n)
}
fmt.Println(result)
}
With an actual array with fixed dimensions known at compile-time, you can do something like:
var result [5][5]int
but this is not the case you have.

Find the most frequent character in text

I need to implement a package with interface with methods that take text file and performs analysis on it - counts the total amount of characters and finds the most frequent symbol and word. To find the most frequent character I loop through each rune in the text, convert it to string and append it as a key to map. The value is an incremented counter which counts how often this character occurs in the given text. Now I'm stuck a little with the following problem -- I can't figure out how to get the key with the highest value in my map. Here's the code:
package textscanner
import (
"fmt"
"log"
"io/ioutil"
"unicode/utf8"
"strconv"
)
// Initializing my scanner
type Scanner interface {
countChar(text string) int
frequentSym(text string) // Return value is not yet implemented
Scan()
Run()
}
/* method counting characters */
func countChar(sc Scanner, text string) int { ... }
func frequentSym(sc Scanner, text string) {
// Make a map with string key and integer value
symbols := make(map[string] int)
// Iterate through each char in text
for _, sym := range text {
// Convert rune to string
char := strconv.QuoteRune(sym)
// Set this string as a key in map and assign a counter value
count := symbols[char]
if count == symbols[char] {
// increment the value
symbols[char] = count + 1
} else {
symbols[char] = 1
}
}
}
So, basically I need to find a pair with the highest int value and return a string key that corresponds to it, that is the most frequent character in text
Just iterate over the map:
maxK := ""
maxV := 0
for k, v := range symbols {
if v > maxV {
maxV = v
maxK = k
}
}
// maxK is the key with the maximum value.
Expanding on #Ainar-G answer, if there is a possibility that your map could contain multiple keys that occur the same number of times, then #Ainar-G code could return different results every time because Go maps are inherently unordered; in other words, the first key in your map to have a value higher then all previous values becomes the highest key, but you don't always know whether that value will occur first in the map. See this as an example.
In order for the code to be deterministic, you will need to address the case where two keys have the same value. A simple implementation would be to do a string comparison if the value is the same.
maxK := ""
maxV := 0
for k, v := range symbols {
if v > maxV || (v == maxV && k < maxK) {
maxV = v
maxK = k
}
}

How to fix 'declared but not used' compiler error in this simple program?

I am trying to learn Go. I really don't understand why the compiler is saying that I am not using a variable. It seems to me that I am using the variable as an argument to Println.
My textbook states:
In this for loop i represents the current position in the array and
value is the same as x[i]
package main
import "fmt"
func main() {
x := [5]float64{ 1,2,3,4,5 }
i := 0
var total float64 = 0
for i, value := range x {
total += value
fmt.Println(i, value)
}
fmt.Println("Average:", total / float64(len(x)))
}
Output on OS X:
go run main.go
# command-line-arguments
./main.go:8: i declared and not used
Surely this fmt.Println(i, value) is using the variable i?
How to fix the compiler message?
Remove the outer i from your program:
package main
import "fmt"
func main() {
x := [5]float64{1, 2, 3, 4, 5}
var total float64 = 0
for i, value := range x {
total += value
fmt.Println(i, value)
}
fmt.Println("Average:", total/float64(len(x)))
}
Surely this fmt.Println(i, value) is using the variable i?
Yes, but the one you're defining inside the for loop. (note the :=), here:
for i, value := range x
^ ^
The outer variable i is never used.

Resources