英文:
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"}]
结果是:
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"
 }
}
我该如何清理映射切片,使其只包含唯一的元素?
英文:
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:
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 slice of maps to contain only unique elements?
答案1
得分: 3
一种选择是将键值对直接解组为可比较的类型,比如结构体:
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
}
一旦你可以逐个比较元素,你还可以将其包装在一个集合中,在解组时过滤元素。在这里隐式地进行过滤,或者事后进行过滤,这是一个意见问题。将过滤作为自己的方法可能更好地分离关注点,但为了简洁起见,我将其包含在UnmarshalJSON中。
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
}
然后你可以解组为Elems:
elems := Elems{}
err := json.Unmarshal(js, &elems)
if err != nil {
	log.Fatal(err)
}
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:
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}]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论