首頁  >  文章  >  後端開發  >  `sort.Slice` 順序是不確定的

`sort.Slice` 順序是不確定的

王林
王林轉載
2024-02-10 12:12:101098瀏覽

`sort.Slice` 顺序是不确定的

php小編草莓將為您介紹關於`sort.Slice`函數的一些重要資訊。在Go語言中,`sort.Slice`函數用於對切片進行排序,但其排序結果的順序是不確定的。也就是說,對於相同的輸入切片,每次排序的結果可能會有所不同。這是因為`sort.Slice`函數使用了快速且有效率的排序演算法,但排序的具體順序是基於輸入資料的特定條件而定的。因此,在使用`sort.Slice`函數時,我們應該注意到排序結果的不確定性,以避免在依賴特定排序順序的場景中出現問題。

問題內容

我正在嘗試使用 go 標準庫中的 sort.slice 對字串切片進行排序。我希望它們按字母順序排序,除了我希望空字串出現在所有其他字串之後(因此我不能只使用 sort.strings)。

對於 less 函數,我認為這會起作用:

func(i, j int) bool {
    return s[j] == "" || s[i] < s[j]
}

但是,根據輸入順序,我似乎得到了隨機答案。這是 mwe:

package main

import (
    "fmt"
    "math/rand"
    "sort"
    "time"
)

func main() {
    s := []string{"", "foo", "bar", "baz"}

    rand.seed(time.now().unix())
    rand.shuffle(len(s), func(i, j int) {
        s[i], s[j] = s[j], s[i]
    })
    fmt.printf("%q\n", s)

    sort.slice(s, func(i, j int) bool {
        return s[j] == "" || s[i] < s[j]
    })
    fmt.printf("%q\n", s)
}

這是運行幾次的輸出:

$ go run ./z
["" "foo" "baz" "bar"]
["bar" "baz" "foo" ""]
$ go run ./z
["baz" "" "foo" "bar"]
["bar" "" "baz" "foo"]
$ go run ./z
["bar" "foo" "" "baz"]
["" "bar" "baz" "foo"]
$ go run ./z
["bar" "foo" "baz" ""]
["" "bar" "baz" "foo"]

解決方法

這是因為您的 less() 函數沒有說出您想要的內容。

您說您希望將空字串排序在所有非空字串之後。你的邏輯:

return s[j] == "" || s[i] < s[j]

這確實告訴我們第二個是否是 "",那麼第一個就更少。這或多或少是正確的(除非兩者都是空的,「is-less」並不是真的:它們是相等的)。但是,如果第一個是 "" 而第二個不是怎麼辦?那麼你的函數應該回傳 false 但它回傳 s[i] < s[j]。如果第二個不為空,則為 true,告訴 "" 小於另一個,與你想要的正好相反。

正確的「is-less」關係是這樣的:

sort.slice(s, func(i, j int) bool {
    if s[j] == "" && s[i] != "" {
        return true
    }
    if s[i] == "" && s[j] != "" {
        return false
    }
    return s[i] < s[j]
})

如果只有第二個是 "",則您希望第一個更少。如果只有第一個是空的,您希望它“不少於”。否則使用正常順序(按位元組)。

go playground 上嘗試。

請注意,如果第一個和第二個值都為空,則此函數將傳回false,因為"" 小於"" (它們相等)。這是要傳回的正確值,儘管在此處傳回 true 仍會導致正確的順序(交換空元素將導致相同的結果),但這可能會導致更少的交換。

使用 xor 轉換邏輯

請注意,在自訂邏輯中,如果只有一個字串為空,則會偏離正常順序。這是邏輯異或(異或)關係a xor btrue 如果只有a 或只有btrue。在 go 中,沒有邏輯 xor 運算符,但 a xor b 相當於 a != b

如果「偵測到」一個空字串,如果第二個空字串為空,則結果為 true(否則為 false)。因此我們可以將這種身分轉換應用到我們的邏輯中:

sort.Slice(s, func(i, j int) bool {
    // Move empty elements to the end:
    if (s[i] == "") != (s[j] == "") { // If only one is empty
        return s[j] == ""
    }
    return s[i] < s[j]
})

這更短並且可能更有效率,但正如您所看到的,它更難理解。僅當效能很重要時才使用此選項。在 go playground 上嘗試這個。

以上是`sort.Slice` 順序是不確定的的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除