在 Golang 中从数组中选择元素的最惯用方法?

新手上路,请多包涵

我有一个字符串数组,我想排除以 foo_ 或长度超过 7 个字符的值。

我可以遍历每个元素,运行 if 语句,然后将它添加到一个切片中。但我很好奇是否有一种惯用的或更像 golang 的方式来实现这一点。

举个例子,在 Ruby 中可以做同样的事情

my_array.select! { |val| val !~ /^foo_/ && val.length <= 7 }

原文由 user2490003 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 514
2 个回答

没有像 Ruby 中那样的单行代码,但是使用辅助函数可以使它几乎一样短。

这是我们的辅助函数,它遍历一个切片,只选择并返回满足函数值捕获的条件的元素:

 func filter(ss []string, test func(string) bool) (ret []string) {
    for _, s := range ss {
        if test(s) {
            ret = append(ret, s)
        }
    }
    return
}

使用这个辅助函数你的任务:

 ss := []string{"foo_1", "asdf", "loooooooong", "nfoo_1", "foo_2"}

mytest := func(s string) bool { return !strings.HasPrefix(s, "foo_") && len(s) <= 7 }
s2 := filter(ss, mytest)

fmt.Println(s2)

输出(在 Go Playground 上尝试):

 [asdf nfoo_1]

笔记:

如果预期会选择许多元素,那么预先分配一个“大” ret 切片并使用简单赋值而不是 append() 可能会有利可图。在返回之前,将 ret 切片,使其长度等于所选元素的数量。

笔记2:

在我的示例中,我选择了一个 test() 函数来判断是否要返回一个元素。所以我不得不颠倒你的“排除”条件。显然,您可以编写辅助函数来期望一个测试函数告诉要排除什么(而不是包括什么)。

原文由 icza 发布,翻译遵循 CC BY-SA 4.0 许可协议

看看 robpike 的过滤器库。这将允许您执行以下操作:

 package main

import (
    "fmt"
    "strings"
    "filter"
)

func isNoFoo7(a string) bool {
    return ! strings.HasPrefix(a, "foo_") && len(a) <= 7
}

func main() {
    a := []string{"test", "some_other_test", "foo_etc"}
    result := Choose(a, isNoFoo7)
    fmt.Println(result) // [test]
}

有趣的是 Rob 的 README.md:

我想看看在 Go 中实现这种东西有多难,并使用我能管理的尽可能好的 API。这并不难。几年前写了它,我还没有机会使用它一次。相反,我只使用“for”循环。你也不应该使用它。

所以根据 Rob 的说法,最惯用的方式是这样的:

 func main() {
    a := []string{"test", "some_other_test", "foo_etc"}
    nofoos := []string{}
    for i := range a {
        if(!strings.HasPrefix(a[i], "foo_") && len(a[i]) <= 7) {
            nofoos = append(nofoos, a[i])
        }
    }
    fmt.Println(nofoos) // [test]
}

这种风格与任何 C 系列语言采用的方法即使不完全相同也非常相似。

原文由 Elwin Arens 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题