dongshan4316
dongshan4316
2019-05-29 10:36
浏览 82
已采纳

根据另一个切片中元素的顺序对切片进行排序

I am attempting to order a slice based on the order of the elements within another slice. My sort function works when I only have one of each type within my slice I want to order however when I start adding more elements the ordering breaks.

I have created an example within the Golang playground.

https://play.golang.org/p/e9sHIeV2qSf

I want to order my Variant slice by the Code field and have it the same as order as the codes appear in the Language struct.

Below is the sort function I am using:

sort.Slice(variants, func(i, j int) bool {
    for k, language := range languages {
        if language.Code == variants[i].Code {
            return i >= k
        }
    }

    return false
})

The current order it's returning is:

Sorted slice: [{Code:en-GB} {Code:en-US} {Code:en-GB} {Code:es-ES} {Code:en-GB} {Code:en-GB} {Code:en-GB} {Code:en-GB} {Code:es-ES}]

When the order within my Language struct is:

"en-GB", "en-US", "fr-FR", "es-ES"

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dongtou2016
    dongtou2016 2019-05-29 10:44
    已采纳

    I think to do this, you need to build a ranking of your languages:

    var langMap map[string]int
    for i, lang := range languages {
        langMap[lang.Code] = i
    }
    

    With this, it becomes trivial to just look up the ranking of each item in variants, and return the appropriate value:

    sort.Slice(variants, func(i, j int) bool {
        iRank, jRank := langMap[variants[i].Code], langMap[variants[j].Code]
        return iRank < jRank
    })
    

    If there's a chance you may have inputs that are not in the pre-sorted list, you can sort them last:

    sort.Slice(variants, func(i, j int) bool {
        iRank, iExists := langMap[variants[i].Code]
        jRank, jExists := langMap[variants[j].Code]
        switch (
        case iExists && jExists:
            // Both exist in the pre-ordered list, so sort by rank
            return iRank < jRank
        case !iExists && !jExists:
            // Neither exists in the pre-ordered list, sort alphabetically
            return variants[i].Code < variants[j].Code
        case iExists:
            // Only i exists, so sort it before j
            return true
        default: // jExists
            // Only j exists, so sort it after i
            return false
        )
    
    })
    

    It is logically possible to do the same by looping through your reference list each time, as you're attempting, but it's much harder to reason about, and far less efficient.

    点赞 评论

相关推荐