Search code examples
functiongoslicefunction-pointersfunctor

Concise Golang way to search key property within slice of an object


I created 3 search functions:

func containsRole(x string, a []Role) bool {
    for _, n := range a {
        if x == n.Name {
            return true
        }
    }
    return false
}
func containsWorkflow(x string, a []SuperWorkflow) bool {
    for _, n := range a {
        if x == n.Workflow.Name {
            return true
        }
    }
    return false
}
func containsPermission(x string, a []Permission) bool {
    for _, n := range a {
        if x == n.URN {
            return true
        }
    }
    return false
}

I'm calling them in a loop in 3 other different functions like:

// In function 1
for _, leftRole := range leftRoles {
    if !containsRole(leftRole.Name, rightRoles) {
        createRoleReport(leftRole))
    }
}
// In function 2
for _, leftWF := range leftWorkflows {
    if !containsWorkflow(leftWF.Workflow.Name, rightWorkflows) {
        createWorkflowReport(leftWF)
    }
}
// In function 3
for _, leftPerm := range leftPermissions {
    if !containsPermission(leftPerm.URN, rightPermissions) {
        createPermissionReport(leftPerm)
    }
}

The properties of structs: Role.Name, SuperWorkflow.Workflow.Name and Permission.URN are string unique keys.
Is there a concise way in Golang, using function pointer or something, to use only one function instead of 3 containsRole(), containsWorkflow(), and containsPermission() and reduce duplication?


Solution

  • Those are the cleanest and most efficient solutions until generics arrive.

    The properties of structs: Role.Name, SuperWorkflow.Workflow.Name and Permission.URN are string unique keys.

    You could sort the slices by the unique key, so you could use binary search when looking for an element, see sort.Search().

    Also you could store them in a map, mapped from the unique key, and the contains operation becomes a simple map indexing, e.g. !containsRole() would be:

    if _, ok := roles[x]; !ok {
        // there is no role with Name == x
    }
    

    This map lookup will be superior in speed compared to your sequential search algorithm, and will most likely beat the binary search too.

    (You wouldn't have to add a function for it of course, just index the map where you need to know if x is contained in it.)