Home > Software engineering >  Aggregate a map of objects by key
Aggregate a map of objects by key

Time:09-27

I am trying to create a map of objects from two maps in Go.

The first Map holds the keys. The second Map has objects with the keys as values.

Basically in this example - there are rules and detection of these rules. In the end - I want a map with the rule names as keys and a map of detections attached to them (aggregating them).

In the end: I want something like this (taken from the Typescript example below):

[LOG]: {
  "rule1": [
    {
      "name": "rule1",
      "message": "I found rule1"
    },
    {
      "name": "rule1",
      "message": "I found rule1 again"
    }
  ],
  "rule2": [
    {
      "name": "rule2",
      "message": "I found rule2"
    },
    {
      "name": "rule2",
      "message": "I found rule2 again"
    },
    {
      "name": "rule2",
      "message": "I found rule2 another time"
    }
  ]
} 

In order to show this I have created this in Typescript:

Typescript Playground

When I am trying to to the same in Go - I somewhat have a mental block, to do this:

Go Playground

package main

import (
    "fmt"
)

type Rule struct {
    Name string `json:"name"`
}

type Detection struct {
    Name    string `json:"name"`
    Message string `json:"message"`
}

func main() {

    rules := []Rule{
        {
            Name: "rule1",
        },
        {
            Name: "rule2",
        },
    }

    detected := []Detection{
        {
            Name:    "rule1",
            Message: "I found rule1",
        },
        {
            Name:    "rule1",
            Message: "I found rule1 again",
        },
        {
            Name:    "rule2",
            Message: "I found rule2",
        },
        {
            Name:    "rule2",
            Message: "I found rule2 again",
        },
        {
            Name:    "rule2",
            Message: "I found rule2 another time",
        },
    }

    fmt.Println(rules)
    fmt.Println(detected)

    aggregatedDetections := map[string][]Detection{}

    for _, r := range rules {
        fmt.Printf("Assign %s to aggregatedDetections\n", r.Name)
    }

    fmt.Println(aggregatedDetections)

}

I understand, that a Go veteran will need < 1 Minute for this ;) However: Even though I think I have the basic idea of maps in go - I do no know what is expected here. Especially how I can assign empty array values in the map, in order to populate them in the next step.

My question is finally: How can I get the desired output.

CodePudding user response:

You can check if a map element is exists with if _, found := map[element]; found {} then if not, create it with an empty slice. Then you can add the elements to the slice.

See code:

package main

import (
    "fmt"
)

type Rule struct {
    Name string `json:"name"`
}

type Detection struct {
    Name    string `json:"name"`
    Message string `json:"message"`
}

func main() {

    rules := []Rule{
        {
            Name: "rule1",
        },
        {
            Name: "rule2",
        },
    }

    detected := []Detection{
        {
            Name:    "rule1",
            Message: "I found rule1",
        },
        {
            Name:    "rule1",
            Message: "I found rule1 again",
        },
        {
            Name:    "rule2",
            Message: "I found rule2",
        },
        {
            Name:    "rule2",
            Message: "I found rule2 again",
        },
        {
            Name:    "rule2",
            Message: "I found rule2 another time",
        },
    }

    fmt.Println(rules)
    fmt.Println(detected)

    aggregatedDetections := make(map[string][]Detection)

    for _, r := range rules {
        if _, found := aggregatedDetections[r.Name]; !found {
          aggregatedDetections[r.Name] = make([]Detection, 0)
        }
        msg := ""
        switch {
          case len(aggregatedDetections[r.Name]) == 0:
             msg = "I found "   r.Name
          case len(aggregatedDetections[r.Name]) == 1:
             msg = "I found "   r.Name " again"
        default:             
             msg = "I found "   r.Name " another time"
        }
        aggregatedDetections[r.Name] = append(aggregatedDetections[r.Name], Detection{
          Name: r.Name,
          Message: msg,
        })
        fmt.Printf("Assign %s to aggregatedDetections\n", r.Name)
    }

    fmt.Println(aggregatedDetections)

}

Playground

  •  Tags:  
  • go
  • Related