将JSON解组成具有唯一元素的映射切片

huangapple go评论110阅读模式
英文:

Unmarshal JSON into slice of maps with unique elements

问题

我正在将一些JSON文件解组成[]map[string]string{},但是很多时候源数据中有很多重复的相同对象。

输入的样子是这样的:

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

结果是:

  1. map[sa1:8172]
  2. ([]map[string]string) (len=9 cap=9) {
  3. (map[string]string) (len=1) {
  4. (string) (len=3) "sa1": (string) (len=4) "8172"
  5. },
  6. (map[string]string) (len=1) {
  7. (string) (len=3) "sa3": (string) (len=4) "8175"
  8. },
  9. (map[string]string) (len=1) {
  10. (string) (len=3) "sa1": (string) (len=4) "8172"
  11. },
  12. (map[string]string) (len=1) {
  13. (string) (len=3) "sa3": (string) (len=4) "8175"
  14. },
  15. (map[string]string) (len=1) {
  16. (string) (len=3) "sa3": (string) (len=4) "8175"
  17. },
  18. (map[string]string) (len=1) {
  19. (string) (len=3) "sa3": (string) (len=4) "8175"
  20. },
  21. (map[string]string) (len=1) {
  22. (string) (len=3) "sa1": (string) (len=4) "8172"
  23. },
  24. (map[string]string) (len=1) {
  25. (string) (len=3) "sa3": (string) (len=4) "8175"
  26. },
  27. (map[string]string) (len=1) {
  28. (string) (len=3) "sa3": (string) (len=4) "8175"
  29. }
  30. }

我该如何清理映射切片,使其只包含唯一的元素?

英文:

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

The input looks like:

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

Resulting in:

  1. map[sa1:8172]
  2. ([]map[string]string) (len=9 cap=9) {
  3. (map[string]string) (len=1) {
  4. (string) (len=3) "sa1": (string) (len=4) "8172"
  5. },
  6. (map[string]string) (len=1) {
  7. (string) (len=3) "sa3": (string) (len=4) "8175"
  8. },
  9. (map[string]string) (len=1) {
  10. (string) (len=3) "sa1": (string) (len=4) "8172"
  11. },
  12. (map[string]string) (len=1) {
  13. (string) (len=3) "sa3": (string) (len=4) "8175"
  14. },
  15. (map[string]string) (len=1) {
  16. (string) (len=3) "sa3": (string) (len=4) "8175"
  17. },
  18. (map[string]string) (len=1) {
  19. (string) (len=3) "sa3": (string) (len=4) "8175"
  20. },
  21. (map[string]string) (len=1) {
  22. (string) (len=3) "sa1": (string) (len=4) "8172"
  23. },
  24. (map[string]string) (len=1) {
  25. (string) (len=3) "sa3": (string) (len=4) "8175"
  26. },
  27. (map[string]string) (len=1) {
  28. (string) (len=3) "sa3": (string) (len=4) "8175"
  29. }
  30. }

How could I clean the slice of maps to contain only unique elements?

答案1

得分: 3

一种选择是将键值对直接解组为可比较的类型,比如结构体:

  1. type Elem struct {
  2. k string
  3. v string
  4. }
  5. func (e *Elem) UnmarshalJSON(d []byte) error {
  6. m := map[string]string{}
  7. if err := json.Unmarshal(d, &m); err != nil {
  8. return err
  9. }
  10. for k, v := range m {
  11. e.k = k
  12. e.v = v
  13. return nil
  14. }
  15. return nil
  16. }

一旦你可以逐个比较元素,你还可以将其包装在一个集合中,在解组时过滤元素。在这里隐式地进行过滤,或者事后进行过滤,这是一个意见问题。将过滤作为自己的方法可能更好地分离关注点,但为了简洁起见,我将其包含在UnmarshalJSON中。

  1. type Elems []Elem
  2. func (e *Elems) UnmarshalJSON(d []byte) error {
  3. tmp := []Elem{}
  4. err := json.Unmarshal(d, &tmp)
  5. if err != nil {
  6. return err
  7. }
  8. seen := map[Elem]bool{}
  9. for _, elem := range tmp {
  10. if seen[elem] {
  11. continue
  12. }
  13. seen[elem] = true
  14. *e = append(*e, elem)
  15. }
  16. return nil
  17. }

然后你可以解组为Elems

  1. elems := Elems{}
  2. err := json.Unmarshal(js, &elems)
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. fmt.Println(elems)

这将给你两个唯一的键值对:[{sa1 8172} {sa3 8175}]

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

英文:

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

  1. type Elem struct {
  2. k string
  3. v string
  4. }
  5. func (e *Elem) UnmarshalJSON(d []byte) error {
  6. m := map[string]string{}
  7. if err := json.Unmarshal(d, &m); err != nil {
  8. return err
  9. }
  10. for k, v := range m {
  11. e.k = k
  12. e.v = v
  13. return nil
  14. }
  15. return nil
  16. }

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.

  1. type Elems []Elem
  2. func (e *Elems) UnmarshalJSON(d []byte) error {
  3. tmp := []Elem{}
  4. err := json.Unmarshal(d, &tmp)
  5. if err != nil {
  6. return err
  7. }
  8. seen := map[Elem]bool{}
  9. for _, elem := range tmp {
  10. if seen[elem] {
  11. continue
  12. }
  13. seen[elem] = true
  14. *e = append(*e, elem)
  15. }
  16. return nil
  17. }

Then you can unmarshal into Elems:

  1. elems := Elems{}
  2. err := json.Unmarshal(js, &elems)
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. fmt.Println(elems)

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

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

huangapple
  • 本文由 发表于 2022年11月11日 22:01:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/74403623.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定