ruk·si

🐹 Go
Functional Functions

Updated at 2014-01-24 11:11

Go does not have generics so it is more complicated to build a general purpose "functional programming" library like Underscore for JS or LINQ for C#. But you can define these functions for data types you need.

package main

import (
    "fmt"
    "strings"
    "unicode"
)

// Returns the first index where given value is found, or -1 if not found.
func Index(values []string, other string) int {
    for i, value := range values {
        if value == other {
            return i
        }
    }
    return -1
}

// Returns true if given value is found in the slice.
func Include(values []string, other string) bool {
    return Index(values, other) >= 0
}

// Returns true if one elements fulfil the given function.
func Any(values []string, f func(string) bool) bool {
    for _, value := range values {
        if f(value) {
            return true
        }
    }
    return false
}

// Returns true if all elements fulfil the given function.
func All(values []string, f func(string) bool) bool {
    for _, value := range values {
        if !f(value) {
            return false
        }
    }
    return true
}

// Form a new slice that only contains elements that fulfil the given function.
func Filter(values []string, f func(string) bool) []string {
    filttered := make([]string, 0)
    for _, value := range values {
        if f(value) {
            filttered = append(filttered, value)
        }
    }
    return filttered
}

// Form a new slice after applying given function to each element.
func Map(values []string, f func(string) string) []string {
    mapped := make([]string, len(values))
    for i, value := range values {
        mapped[i] = f(value)
    }
    return mapped
}

// Returns the element which has the highest score using given evaluator.
func Max(values []string, f func(string) int) (string, int, bool) {
    var maxValue string
    var maxScore int
    var wasFound = false
    for _, value := range values {
        score := f(value)
        if score > maxScore {
            maxValue = value
            maxScore = score
            wasFound = true
        }
    }
    return maxValue, maxScore, wasFound
}

var p = fmt.Println

func main() {
    var fruits = []string{"peach", "apple", "pear", "plum"}

    p(Index(fruits, "pear"))   // => 2, "pear" is at string[2]
    p(Index(fruits, "orange")) // => -1, "orange" does not exist

    p(Include(fruits, "plum"))  // => true
    p(Include(fruits, "grape")) // => false

    p(Any(fruits, func(v string) bool {
        return strings.HasPrefix(v, "p")
    }))
    // => true, some of the strings start with "p"

    p(All(fruits, func(v string) bool {
        return strings.HasPrefix(v, "p")
    }))
    // => false, not all of the strings start with "p"

    p(Filter(fruits, func(v string) bool {
        return strings.Contains(v, "e")
    }))
    // => [peach apple pear]

    p(Map(fruits, func(v string) string {
        runes := []rune(v)
        runes[0] = unicode.ToUpper(runes[0])
        str := string(runes)
        return str
    }))
    // => [Peach Apple Pear Plum]

    p(Map(fruits, strings.ToUpper))
    // => [PEACH APPLE PEAR PLUM]

    p(Max(fruits, func(v string) int {
        return len(v)
    }))
    // => peach 5 true

    p(Max([]string{}, func(v string) int {
        return len(v)
    }))
    // => "" 0 false
}