ZetCode

Go 过滤切片

最后修改时间 2024 年 4 月 11 日

在本文中,我们将展示如何在 Golang 中过滤切片。

过滤操作会处理数据结构(例如数组),并生成一个新的数据结构,其中只包含给定谓词返回 true 的元素。

谓词是一个返回布尔值的单参数函数。

Go 过滤切片示例

在下面的示例中,我们过滤掉正数。

positive.go
package main

import (
    "fmt"
)

func main() {

    vals := []int{-2, 0, 1, 9, 7, -3, -5, 6}
    positive := []int{}

    for i := range vals {
        if vals[i] > 0 {
            positive = append(positive, vals[i])
        }
    }

    fmt.Println(positive)
}

我们有一个整数切片。我们从现有切片创建一个新切片,其中只包含其正值。

for i := range vals {
    if vals[i] > 0 {
        positive = append(positive, vals[i])
    }
}

我们使用 for 循环遍历数组的元素。我们测试每个元素是否大于零。所有满足条件的元素都会被复制到新的 positive 切片中。原始切片不会被修改。

$ go run simple.go
[1 9 7 6]

Go 原地过滤切片

在下面的示例中,切片在过滤操作期间被修改。

positive.go
package main

import (
    "fmt"
)

func main() {

    vals := []int{-2, 0, 1, 9, 7, -3, -5, 6}

    n := 0
    for _, val := range vals {
        if isPositive(val) {
            vals[n] = val
            n++
        }
    }

    vals = vals[:n]
    fmt.Println(vals)
}

func isPositive(val int) bool {
    if val > 0 {
        return true
    } else {

        return false
    }
}

该示例修改了 vals 切片,使其只包含正值。没有创建新的切片。

Go 按字符串长度过滤切片

在下面的示例中,我们按字符串长度进行过滤。

fil_strlen.go
package main

import (
    "fmt"
)

func main() {

    words := []string{"sky", "forest", "fly", "cup", "wood",
        "falcon", "so", "see", "tool"}
    filtered := []string{}

    for i := range words {
        if len(words[i]) == 3 {
            filtered = append(filtered, words[i])
        }
    }

    fmt.Println(filtered)
}

在过滤操作中,我们只包含长度为三个字符的单词。

$ go run fil_strlen.go
[sky fly cup see]

Go 过滤结构体切片

在下面的示例中,我们过滤结构体切片。

filter_slice_structs.go
package main

import "fmt"

type User struct {
    name       string
    occupation string
    country    string
}

func main() {

    users := []User{

        {"John Doe", "gardener", "USA"},
        {"Roger Roe", "driver", "UK"},
        {"Paul Smith", "programmer", "Canada"},
        {"Lucia Mala", "teacher", "Slovakia"},
        {"Patrick Connor", "shopkeeper", "USA"},
        {"Tim Welson", "programmer", "Canada"},
        {"Tomas Smutny", "programmer", "Slovakia"},
    }

    var programmers []User

    for _, user := range users {

        if isProgrammer(user) {
            programmers = append(programmers, user)
        }
    }

    fmt.Println("Programmers:")
    for _, u := range programmers {

        fmt.Println(u)
    }
}

func isProgrammer(user User) bool {

    return user.occupation == "programmer"
}

我们有一个用户切片。我们创建一个新的切片,其中只包含程序员。

for _, user := range users {

    if isProgrammer(user) {
        programmers = append(programmers, user)
    }
}

我们遍历 users 切片,如果用户满足 isProgrammer 断言,则将当前用户添加到 programmers 切片中。

func isProgrammer(user User) bool {

    return user.occupation == "programmer"
}

IsProgrammer 断言对于所有 occupation 字段等于 "programmer" 的用户都返回 true。

$ go run filter_slice_structs.go
Programmers:
{Paul Smith programmer Canada}
{Tim Welson programmer Canada}
{Tomas Smutny programmer Slovakia}

Go 过滤切片通用示例

下一个示例有一个更通用的过滤函数。

generic.go
package main

import (
    "fmt"
    "strings"
)

func main() {

    words := []string{"sky", "forest", "fly", "cup", "wood",
        "falcon", "so", "see", "tool"}

    filtered := Filter(words, func(word string) bool {
        return strings.HasPrefix(word, "s")
    })

    fmt.Println(filtered)

    filtered2 := Filter(words, func(word string) bool {
        return len(word) == 3
    })

    fmt.Println(filtered2)
}

func Filter(vs []string, f func(string) bool) []string {
    filtered := make([]string, 0)
    for _, v := range vs {
        if f(v) {
            filtered = append(filtered, v)
        }
    }
    return filtered
}

我们有一个单词切片。我们通过字符串前缀和字符串长度来过滤切片。

$ go run fil_strlen2.go
[sky so see]
[sky fly cup see]

来源

The Go Programming Language Specification

在本文中,我们过滤了 Go 中的切片。

作者

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

列出所有 Go 教程