0

I have to convert map of structure to slice of structure in Golang, i.e. source to target structure specified below.

// Source
var source map[string]Category

type Category struct {
    A           int
    SubCategory map[string]SubCategory
}

type SubCategory struct {
    B int
    C string
}

// Target
var target []OldCategory

type OldCategory struct {
    OldA           int `mapstructure:"A"`
    OldSubCategory []OldSubCategory
}

type OldSubCategory struct {
    OldB int    `mapstructure:"B"`
    OldC string `mapstructure:"C"`
}

I am referring mapstrucuture package ("github.com/mitchellh/mapstructure"). One way to convert from source to target is to iterate on all the SubCategory and then Category in source instance and use mapstructure.Decode() to convert each one individually.

Is there a direct way using mapstrucuture package, wherein I create a custom decoder hook using NewDecoder and DecoderConfig.DecodeHook, and whenever I encounter source as a map of structure and target as a slice of structure, I handle it in the DecodeHookFunc function.

Relevant documentation of mapstructure https://godoc.org/github.com/mitchellh/mapstructure#NewDecoder

Rahul Chawla
  • 190
  • 1
  • 3
  • 14

3 Answers3

1

Use nested for loops:

for _, c := range source {
    oc := OldCategory{OldA: c.A}
    for _, sc := range c.SubCategory {
        oc.OldSubCategory = append(oc.OldSubCategory, OldSubCategory{OldB: sc.B, OldC: sc.C})
    }
    target = append(target, oc)
}
  • This seems to be the iteration approach I was suggesting. The thing is, there are 10-15 fields in each Category and SubCategory. I want to create a generic solution, so that it is easily extendible. So if there is structure change in future, I would want to update only the model file where the structures are stored and not look into the code logic. – Rahul Chawla Jan 25 '20 at 19:03
1

you could do it using mapstructure decoder hooks, write custom logic inside the decoder hook , to do your job. But there is no standard lib function to do your job.

Example:

dc := &mapstructure.DecoderConfig{Result: target, DecodeHook: customHook}
    ms, err := mapstructure.NewDecoder(dc)
    if err != nil {
        return err
    }

    err = ms.Decode(source)
    if err != nil {
        return err
    }

func customHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
if f.Kind() == reflect.Int && t.Kind() == reflect.Bool {
    var result bool
    if data == 1 {
        result = true
    }
    return result, nil

}

So you could technically decode anything to anything using custom hooks as long it has your custom logic.

  • It works, I converted the ```data interface{}``` in customHook to ```[]Category``` when encountered ``` map[string]Category``` and to ``` []SubCategory``` when encountered ``` map[string]SubCategory``` and return these slice from customHook function. The decoder receives slice an input and is able to map it to target slice, ```target []OldCategory``` and ```OldSubCategory []OldSubCategory``` respectively – Rahul Chawla Jan 27 '20 at 16:22
-1

In Go is there a way to convert map of structure to slice of structure

No, there is no language construct or syntactical sugar for this.

Volker
  • 40,468
  • 7
  • 81
  • 87