ZetCode

Golang slices.Sorted

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 slices.Sorted 函数。我们将通过实际示例介绍切片操作,并检查排序顺序。

slices.Sorted 函数用于测试切片是否按升序排序。它是 Go 实验性 slices 包的一部分。

此函数对于验证数据或在执行需要已排序输入的 যেসব操作之前检查先决条件非常有用。它返回一个布尔值。

基本 slices.Sorted 示例

slices.Sorted 最简单的用法是检查整数切片是否按升序排序。该函数不需要额外的参数。

basic_sorted.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 2, 3, 4, 5}
    unsorted := []int{5, 3, 1, 4, 2}
    
    fmt.Println("Numbers sorted:", slices.Sorted(numbers))
    fmt.Println("Unsorted sorted:", slices.Sorted(unsorted))
}

我们创建了两个切片——一个已排序和一个未排序的。该函数能正确识别它们的排序状态。输出分别显示 true 和 false。

检查字符串切片

slices.Sorted 也适用于字符串切片。此示例检查单词切片是否按字母顺序排列。

string_sorted.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    words := []string{"apple", "banana", "cherry"}
    mixed := []string{"zebra", "apple", "banana"}
    
    fmt.Println("Words sorted:", slices.Sorted(words))
    fmt.Println("Mixed sorted:", slices.Sorted(mixed))
}

该函数对字符串使用字典序。第一个切片顺序正确,而第二个切片不正确,因为“zebra”排在“apple”之前。

使用自定义类型

对于自定义类型,我们需要实现 Ordered 接口。此示例演示了如何检查自定义结构切片的排序。

custom_type.go
package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 35},
    }
    
    unsortedPeople := []Person{
        {"Bob", 30},
        {"Alice", 25},
        {"Charlie", 35},
    }
    
    fmt.Println("People sorted:", slices.SortedFunc(people, func(a, b Person) int {
        return a.Age - b.Age
    }))
    
    fmt.Println("Unsorted people:", slices.SortedFunc(unsortedPeople, func(a, b Person) int {
        return a.Age - b.Age
    }))
}

注意:这里我们使用 SortedFunc,因为 Sorted 需要 Ordered 约束。比较函数根据年龄定义我们的排序顺序。

空切片和单元素切片

slices.Sorted 对边缘情况有特殊的行为。空切片和单元素切片始终被视为已排序。

edge_cases.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    empty := []int{}
    single := []string{"alone"}
    
    fmt.Println("Empty sorted:", slices.Sorted(empty))
    fmt.Println("Single element sorted:", slices.Sorted(single))
}

这些情况返回 true,因为没有要比较的元素,或者只有一个元素。这符合已排序的数学定义。

检查降序

要检查降序,我们可以使用带有自定义比较的 slices.SortedFunc。此示例演示了两个方向。

descending.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    asc := []int{1, 2, 3, 4, 5}
    desc := []int{5, 4, 3, 2, 1}
    
    fmt.Println("Ascending sorted:", slices.Sorted(asc))
    fmt.Println("Descending sorted:", slices.IsSortedFunc(desc, func(a, b int) int {
        return b - a // Reverse comparison
    }))
}

标准的 Sorted 只检查升序。对于降序,我们提供一个反转常规顺序的比较函数。

性能注意事项

对于大型切片,slices.Sorted 的性能很重要。此示例在不同切片大小上对该操作进行了基准测试。

performance.go
package main

import (
    "fmt"
    "slices"
    "time"
)

func main() {
    sizes := []int{1_000, 10_000, 100_000}
    
    for _, size := range sizes {
        slice := make([]int, size)
        for i := range slice {
            slice[i] = i
        }
        
        start := time.Now()
        _ = slices.Sorted(slice)
        fmt.Printf("Size %d: %v\n", size, time.Since(start))
    }
}

该函数在找到第一个无序元素时停止。如果前两个元素无序,则最佳情况性能为 O(1)。

实际示例:输入验证

这个实际示例验证了用户提供的数字在处理前已排序。它演示了实际用法。

input_validation.go
package main

import (
    "fmt"
    "slices"
    "strconv"
)

func main() {
    inputs := []string{"10", "20", "15", "30"}
    
    numbers := make([]int, len(inputs))
    for i, s := range inputs {
        num, err := strconv.Atoi(s)
        if err != nil {
            fmt.Println("Invalid input:", s)
            return
        }
        numbers[i] = num
    }
    
    if slices.Sorted(numbers) {
        fmt.Println("Processing sorted numbers...")
        // Perform operations that require sorted input
    } else {
        fmt.Println("Error: Numbers must be provided in sorted order")
    }
}

我们将字符串转换为整数,然后验证它们是否已排序。这种模式在处理需要排序以确保正确性的数据时很常见。

来源

Go 实验性切片包文档

本教程通过实际示例介绍了 Go 中的 slices.Sorted 函数,涵盖了各种场景和数据类型的排序检查。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程