sorting - golang sort.Sort随机输出并且是错误的

标签 sorting go

我有一个应用于结构的自定义排序函数。完整代码是 here on play.golang.org .

type Stmt struct {
    Name  string
    After []string
}

func sortStmts(stmts []Stmt) []Stmt {
    sort.Sort(ByAfter(stmts))
    return stmts
}

type ByAfter []Stmt

func (a ByAfter) Len() int      { return len(a) }
func (a ByAfter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAfter) Less(i, j int) bool {
    isLess := true

    //fmt.Printf("%s.%+v is being compared with %s.%+v\n", a[i].Name, a[i].After, a[j].Name, a[j].After)

    for _, v := range a[i].After {
        if a[j].Name == v {
            isLess = false
            break
        }
    }

    if isLess {
        //fmt.Printf("%s.%+v is Before %s.%+v\n", a[i].Name, a[i].After, a[j].Name, a[j].After)
    } else {
        //fmt.Printf("%s.%+v is After %s.%+v\n", a[i].Name, a[i].After, a[j].Name, a[j].After)
    }

    return isLess
}

我的目的是自动创建一组正确排序的 sql create 语句,以便从属表排在第一位。

所以如果 Stmt{Name: "user_role", After: []string{"user", "role"} } 存在,那么在有序列表中 user_role 应该在 userrole 之后。

在我们开始添加更多值之前,这似乎工作得很好。才进去查了一下,才发现可能是第一次碰巧走运,但确实没有任何一致性。

我在排序函数中做错了什么结果是随机的。我特别想知道为什么“role”项没有出现在“user_role”项之前,即使我已将它指定为 user_role 出现在 role 之后。

最佳答案

您的“Less”函数不可传递。也就是说,如果 A < B 且 B < C,则它也必须满足 A < C。

您无法使用常规排序函数指定部分顺序并获得排序后的输出。相反,您需要实现 topological sort .

这是对您的数据的简单实现(除了我删除了重复的“密码”条目)。

package main

import "fmt"

type Stmt struct {
    Name  string
    After []string
}

func topSort(ss []Stmt) []string {
    after := map[string][]string{} // things that must come after
    counts := map[string]int{}     // number unsatified preconditions
    zc := map[string]struct{}{}    // things with zero count
    for _, s := range ss {
        for _, a := range s.After {
            after[a] = append(after[a], s.Name)
        }
        counts[s.Name] = len(s.After)
        if len(s.After) == 0 {
            zc[s.Name] = struct{}{}
        }
    }

    r := []string{}
    for len(zc) > 0 {
        for n := range zc {
            r = append(r, n)
            for _, a := range after[n] {
                counts[a]--
                if counts[a] == 0 {
                    zc[a] = struct{}{}
                }
            }
            delete(zc, n)
        }
    }
    return r
}

func main() {
    stmts := []Stmt{
        {Name: "app", After: []string{"app_user"}},
        {Name: "billingplan", After: []string{}},
        {Name: "campaign", After: []string{"app_user"}},
        {Name: "campaign_app", After: []string{"campaign", "app"}},
        {Name: "campaign_ip", After: []string{"campaign", "ip"}},
        {Name: "campaign_operator", After: []string{"campaign", "operator"}},
        {Name: "campaign_sponsor", After: []string{"campaign", "sponsor"}},
        {Name: "campaign_subscriberfilter", After: []string{"campaign", "subscriber_filters"}},
        {Name: "campaign_url", After: []string{"campaign", "url"}},
        {Name: "contentpartner", After: []string{"app_user"}},
        {Name: "filter_criteria", After: []string{"campaign", "subscriber_filters"}},
        {Name: "ip", After: []string{"app_user"}},
        {Name: "mobile_registered", After: []string{"campaign", "app"}},
        {Name: "operator", After: []string{}},
        {Name: "passwords", After: []string{"app_user"}},
        {Name: "publish_package", After: []string{}},
        {Name: "role", After: []string{}},
        {Name: "sponsor", After: []string{"app_user"}},
        {Name: "subscriber_dbs", After: []string{}},
        {Name: "subscriber_filters", After: []string{"subscriber_dbs"}},
        {Name: "timezone", After: []string{}},
        {Name: "url", After: []string{"app_user"}},
        {Name: "app_user", After: []string{}},
        {Name: "user_role", After: []string{"app_user", "role"}},
    }
    r := topSort(stmts)
    for _, s := range r {
        fmt.Println(s)
    }
}

关于sorting - golang sort.Sort随机输出并且是错误的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29025460/

相关文章:

java - 使用抽象类时如何使用比较器?

rest - 如何使用证书 golang 发送 https 请求

xml - 如何更改 struct XML 标签?

go - 停止单个goroutine的最佳方法?

javascript - 如何将 true 或 false 的 const 列表排序为两个单独的数组,一个包含 true 对象,另一个包含 false 对象?

Javascript 自然排序数组/对象并维护索引关联

python - Pandas:没有排序索引和列的数据透视表

java - 通过ArrayLists排序,代码问题

go - 如何理解这个例子中的 goroutines 执行?

go - 在 Go 中设置工厂模式