網頁

2021/8/21

Golang foreach filter 範例

Go並沒有類似JavaScript及Java lambda內建用來遍歷集合或陣列的forEach及依條件篩選陣列元素的filter,需要的時候只能自己用for迴圈實作。


範例環境:

  • Go 1.16

struct EmployeeDepartmentmodel package。

model.go

package model

type Employee struct {
    Id   int
    Name string
    Age  int
}

type Department struct {
    Id        int
    Name      string
    Employees []Employee
}

下面getDeps()用來產生[]Department slice資料。
foreach()負責遍歷slice,參數filter函式用來篩選[]Department符合條件的元素;
isAllEmpLess30()filter函式的實例。

main.go

package main

import (
    "fmt"

    "abc.com/demo/model"
)

func main() {
    deps := getDeps()
    result := foreach(deps, isAllEmpLess30)
    fmt.Println(result)
}

func getDeps() (deps []model.Department) {
    deps = []model.Department{
        {
            Id:   1,
            Name: "HR",
            Employees: []model.Employee{
                {Id: 1, Name: "John", Age: 33},
                {Id: 2, Name: "Mary", Age: 28},
            },
        },
        {
            Id:   2,
            Name: "Mkt.",
            Employees: []model.Employee{
                {Id: 3, Name: "Bill", Age: 18},
                {Id: 4, Name: "Nick", Age: 17},
            },
        },
    }
    return
}

func foreach(deps []model.Department, filter func(dep model.Department) bool) (result []model.Department) {
    for _, dep := range deps {
        if filter(dep) {
            result = append(result, dep)
        }
    }
    return
}

func isAllEmpLess30(dep model.Department) bool {
    emps := dep.Employees
    if emps != nil && len(emps) != 0 {
        for _, emp := range emps {
            return !(emp.Age > 30)
        }
    }
    return true
}

foreach()及函示參數filter改成"Generic"一點(Go沒有泛型(Generic),需要利用空介面interface{}和反射 package reflect功能來替代),不過效能不好。

main.go

package main

import (
    "fmt"
    "reflect"

    "abc.com/demo/model"
)

func main() {
    deps := getDeps()
    result := foreach(deps, func(o interface{}) bool {
        dep, _ := o.(model.Department) // type assertion, convert interface to struct
        emps := dep.Employees
        if emps != nil && len(emps) != 0 {
            for _, emp := range emps {
                return !(emp.Age > 30)
            }
        }
        return true
    })
    fmt.Println(result)
}

func getDeps() (deps []model.Department) {...}

func foreach(arr interface{}, filter func(o interface{}) bool) (result interface{}) {
    typ := reflect.TypeOf(arr)
    vals := reflect.ValueOf(arr)
    for i := 0; i < vals.Len(); i++ {
        if v := vals.Index(i); filter(v.Interface()) {
            result = reflect.Append(reflect.MakeSlice(typ, 0, 0), v)
        }
    }
    return
}


沒有留言:

張貼留言