解析嵌套列表无法进入第三层级。

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

Parsing nested list does not go down to level 3

问题

我有一个表示菜单项的JSON。

菜单项可以有子菜单项,而子菜单项又可以有另一个子菜单项,依此类推。

输入的JSON通过父ID关联菜单项。我试图将其转换为每个菜单项都有其子菜单项的模型。

子菜单项最多有三层。我已经成功解析了前两层,但是不知道为什么第三层没有被解析。我已经为这个问题调试了几个小时了。希望能得到一些帮助。

menu2.sjon

[
  {
    "category_id": 4,
    "category_id_400": "'SCHOO",
    "name": "School Supplies",
    "parent_id": 2,
    "position": 2,
    "level": 2,
    "status": 1,
    "url": "http://www.booksrus.kw/sa-en/school-supplies.html"
  },
  {
    "category_id": 141,
    "category_id_400": "'SCHBA",
    "name": "School Bags",
    "parent_id": 4,
    "position": 12,
    "level": 3,
    "status": 1,
    "url": "http://www.booksrus.kw/sa-en/school-supplies/school-bags.html"
  },
  {
    "category_id": 269,
    "category_id_400": "'AEP",
    "name": "Bags Knapsack with Trolley",
    "parent_id": 141,
    "position": 1,
    "level": 4,
    "status": 1,
    "url": "http://www.booksrus.kw/sa-en/school-supplies/school-bags/bags-knapsack-with-trolley.html"
  }
]

menu.go

package main

import(
	"fmt"
	"encoding/json"
	"io/ioutil"
	"sort"
	"bytes"
)

type MenuItems []MenuItem

func (a MenuItems) Len() int           { return len(a) }
func (a MenuItems) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a MenuItems) Less(i, j int) bool { return a[i].Category_id < a[j].Category_id }

type MenuItem struct{
	Category_id int `json:"category_id"`
	Category_id_400 string `json:"category_id_400"`
	Name string `json:"name"`
	Parent_id int `json:"parent_id"`
	Position int `json:"position"`
	Level int `json:"level"`
	Status int `json:"status"`
	Url string  `json:"url"`
	Subs []MenuItem `json:"subs"`
}

func (m MenuItem) String() string{

	 var buffer bytes.Buffer
	 buffer.WriteString(fmt.Sprintf("%d %s\n",m.Category_id,m.Name))
	for _,s := range m.Subs{
		buffer.WriteString(fmt.Sprintf(">>    %s\n",s.String()));
	}

	return buffer.String()
	//return fmt.Sprintf("CategoryId: %d, ParentId: %d,Name: %s, Sub: %v\n",m.Category_id,m.Parent_id,m.Name,m.Subs);
}

func (m *MenuItem) TryAdd(other MenuItem) bool{

	if other.Parent_id == m.Category_id {
		
		m.Subs = append(m.Subs,other);
		return true
	}else{
		for _,sub := range m.Subs{
			if found := sub.TryAdd(other);found{
				return true
			}
		}
	}

	return false
}

func main() {
	rootItems := make([]MenuItem,0)
	bytes, err := ioutil.ReadFile("menu2.json")

	if err != nil{
		fmt.Printf("Reading: %s\n",err.Error())
		return;
	}

	var menuItems []MenuItem
	err = json.Unmarshal(bytes,&menuItems)

	if err != nil{
		fmt.Println(err.Error())
		return
	}

	sort.Sort(MenuItems(menuItems))
	
	for _,item := range menuItems{
		if item.Parent_id == 2{
			rootItems = append(rootItems,item)
		}else{
			for i:=0;i<len(rootItems);i++{
				if found := rootItems[i].TryAdd(item); found{
					break;
				}else{
					fmt.Printf("No Action: Id: %d, Name: %s, Parent: %d.\n",item.Category_id,item.Name,item.Parent_id)
				}
			}
		}
	}

	fmt.Printf("\nRootitems:\n%s\n",rootItems)
}

输出

Rootitems:
[4      School Supplies
>>    141      School Bags
//第三层应该出现在这里
]
英文:

I have a JSON representing menu items.

A menu item can have a sub menu item, which in turn can have another sub menu item and so son.

The input JSON relates the menu items through a parent id. I'm trying to convert this to a model where each menu item has a slice of its sub menu items.

The sub menus go three levels deep. I've managed to parse upto two levels but I have no idea why the third level isn't being parsed. I've been debugging this problem for hours. I would appreciate some help.

menu2.sjon

[
  {
    &quot;category_id&quot;: 4,
    &quot;category_id_400&quot;: &quot;&#39;SCHOO&quot;,
    &quot;name&quot;: &quot;School Supplies&quot;,
    &quot;parent_id&quot;: 2,
    &quot;position&quot;: 2,
    &quot;level&quot;: 2,
    &quot;status&quot;: 1,
    &quot;url&quot;: &quot;http://www.booksrus.kw/sa-en/school-supplies.html&quot;
  },
  {
    &quot;category_id&quot;: 141,
    &quot;category_id_400&quot;: &quot;&#39;SCHBA&quot;,
    &quot;name&quot;: &quot;School Bags&quot;,
    &quot;parent_id&quot;: 4,
    &quot;position&quot;: 12,
    &quot;level&quot;: 3,
    &quot;status&quot;: 1,
    &quot;url&quot;: &quot;http://www.booksrus.kw/sa-en/school-supplies/school-bags.html&quot;
  },
  {
    &quot;category_id&quot;: 269,
    &quot;category_id_400&quot;: &quot;&#39;AEP&quot;,
    &quot;name&quot;: &quot;Bags Knapsack with Trolley&quot;,
    &quot;parent_id&quot;: 141,
    &quot;position&quot;: 1,
    &quot;level&quot;: 4,
    &quot;status&quot;: 1,
    &quot;url&quot;: &quot;http://www.booksrus.kw/sa-en/school-supplies/school-bags/bags-knapsack-with-trolley.html&quot;
  }
]

menu.go

package main

import(
	&quot;fmt&quot;
	&quot;encoding/json&quot;
	&quot;io/ioutil&quot;
	&quot;sort&quot;
	&quot;bytes&quot;
)

type MenuItems []MenuItem

func (a MenuItems) Len() int           { return len(a) }
func (a MenuItems) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a MenuItems) Less(i, j int) bool { return a[i].Category_id &lt; a[j].Category_id }

type MenuItem struct{
	Category_id int `json:&quot;category_id&quot;`
	Category_id_400 string `json:&quot;category_id_400&quot;`
	Name string `json:&quot;name&quot;`
	Parent_id int `json:&quot;parent_id&quot;`
	Position int `json:&quot;position&quot;`
	Level int `json:&quot;level&quot;`
	Status int `json:&quot;status&quot;`
	Url string  `json:&quot;url&quot;`
	Subs []MenuItem `json:&quot;subs&quot;`
}

func (m MenuItem) String() string{

	 var buffer bytes.Buffer
	 buffer.WriteString(fmt.Sprintf(&quot;%d %s\n&quot;,m.Category_id,m.Name))
	for _,s := range m.Subs{
		buffer.WriteString(fmt.Sprintf(&quot;&gt;	%s\n&quot;,s.String()));
	}

	return buffer.String()
	//return fmt.Sprintf(&quot;CategoryId: %d, ParentId: %d,Name: %s, Sub: %v\n&quot;,m.Category_id,m.Parent_id,m.Name,m.Subs);
}

func (m *MenuItem) TryAdd(other MenuItem) bool{

	if other.Parent_id == m.Category_id {
		
		m.Subs = append(m.Subs,other);
		return true
	}else{
		for _,sub := range m.Subs{
			if found := sub.TryAdd(other);found{
				return true
			}
		}
	}

	return false
}

func main() {
	rootItems := make([]MenuItem,0)
	bytes, err := ioutil.ReadFile(&quot;menu2.json&quot;)

	if err != nil{
		fmt.Printf(&quot;Reading: %s\n&quot;,err.Error())
		return;
	}

	var menuItems []MenuItem
	err = json.Unmarshal(bytes,&amp;menuItems)

	if err != nil{
		fmt.Println(err.Error())
		return
	}

	sort.Sort(MenuItems(menuItems))
	
	for _,item := range menuItems{
		if item.Parent_id == 2{
			rootItems = append(rootItems,item)
		}else{
			for i:=0;i&lt;len(rootItems);i++{
				if found := rootItems[i].TryAdd(item); found{
					break;
				}else{
					fmt.Printf(&quot;No Action: Id: %d, Name: %s, Parent: %d.\n&quot;,item.Category_id,item.Name,item.Parent_id)
				}
			}
		}
	}

	fmt.Printf(&quot;\nRootitems:\n%s\n&quot;,rootItems)
}

Output

Rootitems:
[4 &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;School Supplies
&gt;	141 &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;School Bags
//Third level should appear here
]

答案1

得分: 1

TryAdd函数中的这个循环很可能是你的问题所在:

for _, sub := range m.Subs {
    if found := sub.TryAdd(other); found {
        return true
    }
}

在这个循环中,sub变量实际上是切片元素的副本。你对副本所做的任何更改都不会持久保存到存储在切片中的元素上。

你可以通过不使用元素的副本,而是通过索引引用它来解决这个问题:

for i := range m.Subs {
    if found := m.Subs[i].TryAdd(other); found {
        return true
    }
}
英文:

This loop in the TryAdd function is most probably your issue:

for _, sub := range m.Subs {
    if found := sub.TryAdd(other); found {
        return true
    }
}

The sub variable in this loop is actually a copy of the slice element. Any changes you make there will not persist back to the the element that is stored in the slice.

You should be able to solve this issue by not working with the element's copy, but referencing it by its index instead:

for i := range m.Subs {
    if found := m.Subs[i].TryAdd(other); found {
        return true
    }
}

huangapple
  • 本文由 发表于 2016年1月18日 01:29:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/34841327.html
匿名

发表评论

匿名网友

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

确定