Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

unique elements in a slice of maps

I’m unmarshaling some json files into []map[string]string{}
but very often the source is dirty with many repeated equal objects

[{"sa1":"8172"},{"sa3":"8175"},{"sa1":"8172"},{"sa3":"8175"},{"sa3":"8175"},{"sa3":"8175"},{"sa1":"8172"},{"sa3":"8175"},{"sa3":"8175"}]

resulting into

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

map[sa1:8172]
([]map[string]string) (len=9 cap=9) {
 (map[string]string) (len=1) {
  (string) (len=3) "sa1": (string) (len=4) "8172"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa3": (string) (len=4) "8175"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa1": (string) (len=4) "8172"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa3": (string) (len=4) "8175"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa3": (string) (len=4) "8175"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa3": (string) (len=4) "8175"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa1": (string) (len=4) "8172"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa3": (string) (len=4) "8175"
 },
 (map[string]string) (len=1) {
  (string) (len=3) "sa3": (string) (len=4) "8175"
 }
}

How could i clean the map to contain only unique elements?

>Solution :

One option is to unmarshal the key value pairs directly into a comparable type, like a struct:

type Elem struct {
    k string
    v string
}

func (e *Elem) UnmarshalJSON(d []byte) error {
    m := map[string]string{}
    if err := json.Unmarshal(d, &m); err != nil {
        return err
    }

    for k, v := range m {
        e.k = k
        e.v = v
        return nil
    }
    return nil
}

Once you can compare the elements individually, you could also wrap that in a collection which filters the elements while unmarshaling. Whether to do this implicitly here, or after the fact is a matter of opinion. It may be a better separation of concerns to make filtering its own method, but I included it in UnmarshalJSON for brevity.

type Elems []Elem

func (e *Elems) UnmarshalJSON(d []byte) error {
    tmp := []Elem{}
    err := json.Unmarshal(d, &tmp)
    if err != nil {
        return err
    }

    seen := map[Elem]bool{}
    for _, elem := range tmp {
        if seen[elem] {
            continue
        }
        seen[elem] = true
        *e = append(*e, elem)
    }
    return nil
}

Then you can unmarshal into Elems:

    elems := Elems{}

    err := json.Unmarshal(js, &elems)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(elems)

Which will give you the two unique pairs: [{sa1 8172} {sa3 8175}]

https://go.dev/play/p/U0iqBAjvz-1

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading