Список неизвестной глубины в Go

#arrays #list #dictionary #multidimensional-array #go

#массивы #Список #словарь #многомерный массив #Вперед

Вопрос:

Я пытаюсь получить список категорий из базы данных с неизвестными уровнями глубины. Возможно ли это с помощью map[int][]interface{} и возможно ли это вообще?

 type Category struct {
    ID        int
    Name      string
    ParentID  int
}

func GetCategories(db *gorm.DB) map[int][]interface{} {
    var result = make(map[int][]interface{})
    var categories = []Category{}
    db.Where("parent_id = ?", 0).Find(amp;categories)
    for len(categories) > 0 {
        var ids []int
        for _, cat := range categories {
            ids = append(ids, cat.ID)
            if cat.ParentID == 0 {
                result[cat.ID] = append(result[cat.ID], cat)
            } else {

                // This work only for 2nd level ...
                result[cat.ParentID] = append(result[cat.ParentID], cat)
            }
        }
    }
    return result
}
  

Наилучший результат был бы в массиве JSON. Например:

 [
    {id: 1, name: "Car", Parent: 0, Children: []},
    {id: 2, name: "Boat", Parent: 0, Children: [
        {id: 4, name: "Fast", Parent: 2, Children: []},
        {id: 5, name: "Slow", Parent: 2, Children: [
            {id: 6, name: "ExtraSlow", Parent: 5, Children: []},
        ]},
    ]},
    {id: 3, name: "Rocket", Parent: 0, Children: []}
]
  

Комментарии:

1. Это возможно, но, вероятно, его следует избегать. Тип, который вы ищете, это map[int]interface{} .

2. Можете ли вы обновить вопрос примером вывода для уровней 2/3 ?

Ответ №1:

Я нашел решение! Я добавил фрагмент категорий внутри структуры категорий и запрашиваю каждый уровень глубины из базы данных, хранящейся в [depth][]Categories{} . Наконец, сортировка всех данных снизу вверх.

 type Category struct {
    ID        int
    Name      string
    ParentID  int
    Children  []Category
}

func GetCategories(db *gorm.DB) []Category {

    // Request data from database
    var categories = []Category{}
    var store = [][]Category{}
    db.Where("parent_id = ?", 0).Find(amp;categories)
    for len(categories) > 0 {
        var ids []int
        for _, cat := range categories {
            ids = append(ids, cat.ID)
        }
        store = append(store, categories)
        categories = []Category{}
        db.Where("parent_id in (?)", ids).Find(amp;categories)
    }

    // Sort and move children to parent
    lastLayer := len(store) - 1
    for lastLayer >= 0 {
        if (lastLayer - 1 >= 0) {
            for _, child := range store[lastLayer] {
                for i, parent := range store[lastLayer -1] {
                    if parent.ID == child.ParentID {
                        store[lastLayer -1][i].Children = append(store[lastLayer -1][i].
                            Children, child)
                    }
                }
            }
        }
        lastLayer--;
    }

    return store[0]
}

// Return content as JSON response in WebApp
func Output(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(GetCategories(databaseConnection))
}
  

Ответ №2:

Вы должны просто сохранить каждый элемент на базовом уровне на карте, а затем иметь список всех его дочерних элементов.

Затем вы можете использовать карту так же, как вы бы использовали массив ids .

 func GetCategories(db *gorm.DB) map[int][]interface{} {
    var result = make(map[int][]interface{})
    var categories = []Category{}
    db.Where("parent_id = ?", 0).Find(amp;categories)
    if len(categories) > 0 {
        for _, cat := range categories {
            if _, ok := result[cat.ID]; !ok {
                result[cat.ID] = make([]interface{}, 0, 5)
            }

            if cat.ParentID != 0 {
                if _, ok := result[cat.ParentID]; !ok {
                    result[cat.ParentID] = make([] interface{}, 0, 5)
                }
                result[cat.ParentID] = append(result[cat.ParentID], cat)                
            }
        }
    }
    return result
}
  

Не совсем ясно, что вы хотите сделать, но это поместит всех родителей в запись «0» карты, устраняя необходимость в рекурсивной структуре данных для хранения всех ваших категорий.

Комментарии:

1. При компиляции этого кода возникает ошибка в строке result[cat.ParentID] = append(результат[cat.ParentID], cat)

2. Ошибка: first argument to append must be slice; have interface {}

3. Извините, я допустил ошибку, я отредактировал ответ. Вы должны изменить result[cat.ID] = make([]Category, 0, 5) на result[cat.ID] = make([]interface{}, 0, 5) , а затем выполнить утверждение типа на выходе.