为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
互换的青春 2022-01-17 10:24:55
我有一个字符串数组,我想排除以foo_OR 开头的超过 7 个字符的值。我可以遍历每个元素,运行if语句,并一路将其添加到切片中。但我很好奇是否有一种惯用的或更类似于 golang 的方式来实现这一点。举个例子,在 Ruby 中可以做同样的事情my_array.select! { |val| val !~ /^foo_/ && val.length <= 7 }
查看完整描述

3 回答

?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

没有像 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()函数来判断是否要返回一个元素。所以我不得不颠倒你的“排除”条件。显然,您可以编写辅助函数来期望一个测试器函数,它告诉排除什么(而不是包含什么)。


查看完整回答
反对 回复 2022-01-17
?
慕运维8079593

TA贡献1876条经验 获得超5个赞

看看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 系列语言所采用的方法非常相似,即使不相同。


查看完整回答
反对 回复 2022-01-17
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

今天,我偶然发现了一个令我惊讶的成语。如果要在不分配的情况下就地过滤切片,请使用具有相同后备数组的两个切片:


s := []T{

    // the input

s2 := s

s = s[:0]

for _, v := range s2 {

    if shouldKeep(v) {

        s = append(s, v)

    }

}

这是删除重复字符串的具体示例:


s := []string{"a", "a", "b", "c", "c"}

s2 := s

s = s[:0]

var last string

for _, v := range s2 {

    if len(s) == 0 || v != last {

        last = v

        s = append(s, v)

    }

}

如果您需要保留两个切片,只需替换s = s[:0]为s = nil或s = make([]T, 0, len(s)),具体取决于您是否要append()为您分配。


查看完整回答
反对 回复 2022-01-17
  • 3 回答
  • 0 关注
  • 183 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信