How to initialise a map of maps [duplicate] - dictionary

This question already has answers here:
Nested maps in Golang
(4 answers)
Closed 1 year ago.
I want to count geolocations of IP addresses by country and then by city. The expected output would be something like:
$ cat ips.txt | ./geoips
United States 42
Washington 21
New York 21
China 10
Beijing 10
I came up with this code that uses map of maps to keep the counts:
func main() {
ips := parseIPs(getIPs())
counts := make(map[string]map[string]int)
for _, ip := range ips {
g := &checkip.Geo{}
_, err := g.Check(ip)
if err != nil {
log.Printf("while getting geolocation: %v", err)
continue
}
counts[g.Country][g.City]++
}
fmt.Printf("%v\n", counts)
}
When I build and run it a get an error:
$ cat ips.txt | ./geoips
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
/Users/xxx/geoips/main.go:30 +0x245
I understand the problem is that the 2nd map is not initialised. How do I do that?
Or is there a better way to keep the counts?

Ok, I think got it:
// The following three lines fix the "assignment
// to entry in nil map" runtime error.
if _, ok := counts[g.Country]; !ok {
counts[g.Country] = make(map[string]int)
}
counts[g.Country][g.City]++

Related

Faster method for creating key value pairs

I want to create a mapping from key (string) to value (string[]). I read a file:
gloveEmbeddings := make(map[string][]string)
f, _ := ioutil.ReadFile("./glove.840B.300d.txt")
The file is in the following format:
key0 val0_index0 val0_index1 val0_index2 val0_index3
key1 val1_index0 val1_index1 val1_index2 val1_index3
...
There are two separations, the new line and the space.
First I create a split of the new line:
newlineSplit := strings.Split(string(f), "\n")
Then I split each row with the space and put the first value in the resulting array as the key and the slice of the rest as the value:
for i := 0; i < len(newlineSplit); i++ {
spaceSplit := strings.Split(newlineSplit[i], " ")
gloveEmbeddings[spaceSplit[0]] = spaceSplit[1:]
}
fmt.Println(gloveEmbeddings)
The file is 5.5GB and this loop is taking more than 20 minutes. The goal is to be able to access the value fast given the key. Is there a better way to do this?
EDIT
I reading the file line by line.
gloveEmbeddings := make(map[string][]string)
f, _ := os.Open("./glove.840B.300d.txt")
scanner := bufio.NewScanner(f)
count := 0
for scanner.Scan() {
spaceSplit := strings.Split(scanner.Text(), " ")
gloveEmbeddings[spaceSplit[0]] = spaceSplit[1:]
if count % 10000 == 0 {
fmt.Println(count)
}
count++
}
But the counts stop printing at 2.19 million.
The loop actually runs fast, even the original version that uses ioutil.ReadFile. What was taking long was the fmt.Println(gloveEmbeddings) which was there only for debugging. Reading the file all at once and one line at a time take the same time, about 42-44 s on my machine.

Set multiple threshold on a log based kusto query

I have set up a log-based alert in Microsoft Azure. The deployment of the alerts done via ARM template.
Where you can input your query and set threshold like below.
"triggerThresholdOperator": {
"value": "GreaterThan"
},
"triggerThreshold": {
"value": 0
},
"frequencyInMinutes": {
"value":15
},
"timeWindowInMinutes": {
"value": 15
},
"severityLevel": {
"value": "0"
},
"appInsightsQuery": {
"value": "exceptions\r\n| where A_ != '2000' \r\n| where A_ != '4000' \r\n| where A_ != '3000' "
}
As far as I understand we can only set threshold once ON an entire query.
Questions: I have multiple statements in my query which I am excluding since it's just a noise. But now I want to set a threshold on value 3000 to 5 and also want to set a time-window to 30 in the same query. meaning only exclude 3000 when it occurs 5 times in the last 30 minutes(when query get run).
exceptions
| where A_ != '2000'
| where A_ != '4000'
| where A_ != '3000'
I am pretty sure that I can't set a threshold like this in the query and the only workaround is to create a new alert just for value 3000 and set a threshold in ARM template. I haven't found any heavy threshold/time filters in Aure. Is there any way I can set multiple thresholds and time filters in a single query? which is again getting checked by different threshold and time filetrs in the ARM template.
Thanks.
I don't fully understand your question.
But for your time window question you could do something like
exceptions
| summarize count() by A_, bin(TimeGenerated, 30m)
That way you will get a count of A_ in blocks of 30 minutes.
Another way would be to do:
let Materialized = materialize(
exceptions
| summarize Count=count(A_) by bin(TimeGenerated, 30m)
); 
Materialized | where Count == 10
But then again it all depends on what you would like to achieve
You can easily set that in the query and fire based on the aggregate result.
exceptions
| where timestamp > ago(30m)
| summarize count2000 = countif(A_ == '2000'), count3000 = countif(A_ == '3000'), count4000 = countif(A_ == '4000')
| where count2000 > 5 or count3000 > 3 or count4000 > 4
If the number of results is greater than one than the aggregate condition applies.

Input map data to struct using Golang [duplicate]

This question already has answers here:
JSON and dealing with unexported fields
(2 answers)
Closed 10 months ago.
I want to put my map data to another map data using Golang. however it has struct type.
Here is my code.
birth := make(map[string]interface{})
birth["docType"] = "registerBirth"
birth["agencyCd"] = string(args[0])
birth["birthYmd"] = string(args[1])
birth["lsTypeNm"] = string(args[2])
birth["monthDiff"] = string(args[3])
birth["nationNm"] = string(args[4])
birth["sexNm"] = string(args[5])
birth["regType"] = string(args[9])
birth["regYmd"] = string(args[10])
I want to put this map data to another map but I want to use struct type.
cattle := make(map[string]interface{})
cattle["docType"] = "information"
cattle["birthInfo"] = struct {
birth map[string]interface{}
}{
birth,
}
but, when I get data.. It comes out like this.
{"birthInfo":{},"docType":"information"}
Here Is the example that I want.
"birthInfo": {
"birthYmd": "2018-07-25",
"cattleNo": "cow001",
"docType": "registerBirth",
"farmNo": "farm001",
"flatEartagNo": "eartag123123",
"lsTypeNm": "황소",
"monthDiff": "2018-07",
"nationNm": "austria",
"regType": "직접",
"regYmd": "20185-07-25",
"sexNm": "M"
},
"docType": "information",
...
Thanks in advance.
The problem is with this section of code
cattle["birthInfo"] = struct {
birth map[string]interface{}
}{
birth,
}
The json package can only marshal values that are exported (public / start with a capital letter).
Change the code block to this and it will work:
cattle["birthInfo"] = struct {
Birth map[string]interface{} // note: capital "Birth", exported
}{
birth,
}
Runnable example with exported field name:
https://play.golang.org/p/maTKn95AoGM

Get json with pljson & plsql

I'm trying to chop out some lists from the following json using pljson
my_json := json('{"Order":
{"no": 1, "batch": 2,"id": 3,"quantity": 10,
"sm_pack": [
{
"no": 10,
"id": 1010,
"quantity": 2
},
{
"no": 11,
"id": 1040,
"quantity": 8
}
],
"sm_size": [
{ ....etc etc
However, I can't get it to work?
I can print the data using this syntax:
v_myjson.path('Order.sm_pack').print;
v_myjson.path('Order.sm_pack[1].no').print;
But how can I assing all those different lists to variables for further processing. i tried different versions of "v_list := json_list(my_json.get('Order.sm_pack')) .. my_json.get('sm_pack').. whatever I try its"NULL SELF" and I seem to have turned blind.
Regards
Printing json lists and objects differs from assigning them to some variables to manipulate them. I will try to answer your question through your example as follows:
DECLARE
obj json := json();
obj_1 json := json();
arr json_list := json_list();
val NUMBER;
BEGIN
/*Create your object*/
obj := json('{"Order":{"no":1,"batch":2,"id":3,"quantity":10,"sm_pack":[{"no":10,"id":1010,"quantity":2},{"no":11,"id":1040,"quantity":8}],"sm_size":[{"no":10,"id":1010,"quantity":2},{"no":11,"id":1040,"quantity":8}]}}');
/*Assign object*/
obj_1 :=json(obj.get('Order'));
/*Assign list from within the object*/
arr := json_list(obj_1.get('sm_pack'));
arr.print;
--or
arr := json_list(json(obj.get('Order')).get('sm_pack'));
arr.print;
/*Get object value from within list*/
val := json_ext.get_number(json(arr.get(2)), 'id');
DBMS_OUTPUT.PUT_LINE(VAL);
END;
/
Notice I used get_number function as your values without single quotes, otherwise, I would use get_string.
Hope that helps!

Subtracting time.Duration from time in Go

I have a time.Time value obtained from time.Now() and I want to get another time which is exactly 1 month ago.
I know subtracting is possible with time.Sub() (which wants another time.Time), but that will result in a time.Duration and I need it the other way around.
In response to Thomas Browne's comment, because lnmx's answer only works for subtracting a date, here is a modification of his code that works for subtracting time from a time.Time type.
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("now:", now)
count := 10
then := now.Add(time.Duration(-count) * time.Minute)
// if we had fix number of units to subtract, we can use following line instead fo above 2 lines. It does type convertion automatically.
// then := now.Add(-10 * time.Minute)
fmt.Println("10 minutes ago:", then)
}
Produces:
now: 2009-11-10 23:00:00 +0000 UTC
10 minutes ago: 2009-11-10 22:50:00 +0000 UTC
Not to mention, you can also use time.Hour or time.Second instead of time.Minute as per your needs.
Playground: https://play.golang.org/p/DzzH4SA3izp
Try AddDate:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("now:", now)
then := now.AddDate(0, -1, 0)
fmt.Println("then:", then)
}
Produces:
now: 2009-11-10 23:00:00 +0000 UTC
then: 2009-10-10 23:00:00 +0000 UTC
Playground: http://play.golang.org/p/QChq02kisT
You can negate a time.Duration:
then := now.Add(- dur)
You can even compare a time.Duration against 0:
if dur > 0 {
dur = - dur
}
then := now.Add(dur)
You can see a working example at http://play.golang.org/p/ml7svlL4eW
There's time.ParseDuration which will happily accept negative durations, as per manual. Otherwise put, there's no need to negate a duration where you can get an exact duration in the first place.
E.g. when you need to substract an hour and a half, you can do that like so:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("now:", now)
duration, _ := time.ParseDuration("-1.5h")
then := now.Add(duration)
fmt.Println("then:", then)
}
https://play.golang.org/p/63p-T9uFcZo

Resources