Skip to content

tobyhede/go-underscore

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.

Underscore.go

Move Fast; Optimize Late

A useful collection of Go utilities. Designed for programmer happiness.

TL;DR Sort-of like underscore.js, but for Go

API Documentation

GoDoc is WorkInProgress

⚠️ Warning

This package is in heavy flux at the moment as I work to incorporate feedback from various sources.

:squirrel: Todo

  • godoc
  • contains
  • indexOf
  • worker pools
  • parallel each
  • parallel map with worker pool
  • refactor to make functions first parameter (eg Each func(func(A), []A))
  • handle maps & slices
  • all
  • any
  • none

Typed Functions


Any


Each


Each func(func(A int), []A) Each func(func(A B), []A)

Applies the given iterator function to each element of a collection (slice or map).

If the collection is a Slice, the iterator function arguments are value, index

If the collection is a Map, the iterator function arguments are value, key

EachP is a Parallel implementation of Each and concurrently applies the given iterator function to each element of a collection (slice or map).

  // var Each func(func(value interface{}, i interface{}), interface{})

  var buffer bytes.Buffer

  fn := func(s, i interface{}) {
    buffer.WriteString(s.(string))
  }

  s := []string{"a", "b", "c", "d", "e"}
  Each(fn, s)

  expect := "abcde"

  e := un.Each(fn, s)

  fmt.Printf("%#v\n", e) //"abcde"

Typed Each can be defined using a function type and the MakeEach helper.

Using a Typed Slice

  var EachInt func(func(value, i int), []int)
  MakeEach(&EachInt)

  var sum int

  fn := func(v, i int) {
    sum += v
  }

  i := []int{1, 2, 3, 4, 5}
  EachInt(fn, i)

  fmt.Printf("%#v\n", sum) //15

Using a Typed Map

  var EachStringInt func(func(key string, value int), map[string]int)
  var sum int

  fn := func(v int, k string) {
    sum += v
  }

  m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
  EachStringInt(fn, m)

  fmt.Printf("%#v\n", sum) //15

Of note is the ability to close over variables within the calling scope.

Every


Map


Map func([]A, func(A) B) []B

Applies the given function to each element of a slice, returning a slice of results

The base Map function accepts interface{} types and returns []interface{}

  // Map func(interface{}, func(interface{}) interface{}) []interface{}

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

  fn := func(s interface{}) interface{} {
    return s.(string) + "!"
  }

  m := un.Map(ToI(s), fn)
  fmt.Println(m) //["a!", "b!", "c!", "d!"]

Typed Maps can be defined using a function type and the MakeMap helper.

  Map func([]A, func(A) B) []B

  var SMap func([]string, func(string) string) []string
  un.MakeMap(&SMap)

  m := un.SMap(s, fn)
  fmt.Println(m) //["a!", "b!", "c!", "d!"]

Of note is the return value of Map is a slice of the return type of the applied function.

Partition


Partition func([]A, func(A) bool) ([]A []A)

Partition splits a slice or map based on the evaluation of the supplied function

The base Partition function accepts interface{} types and returns []interface{}

  // Partition func(interface{}, func(interface{}) bool) ([]interface{}, []interface{})

  s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

  fn := func(i interface{}) bool {
    return (i.(int) % 2) == 1
  }

  odd, even := un.Partition(s, fn)

  fmt.Println(odd)  //[1, 3, 5, 7, 9]
  fmt.Println(even) //[2, 4, 6, 8, 10]

Typed Partitions can be defined using a function type and the MakePartition helper.

  // Partition func([]A, func(A) bool) ([]A []A)

  var IPartition func([]int, func(int) bool) ([]int, []int)

  un.MakePartition(&IPartition)

  s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

  fn := func(i int) bool {
    return (i % 2) == 1
  }

  odd, even := un.IPartition(s, fn)

  fmt.Println(odd)  //[1, 3, 5, 7, 9]
  fmt.Println(even) //[2, 4, 6, 8, 10]

Contains returns true if an object is in a slice.

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

  b := un.Contains(s, o)
  fmt.Println(b) //true

ToI converts a slice of arbitrary type []T into a slice of []interfaces{}

  s := []int{1, 1, 3, 5, 8, 13}
  i := un.ToI(s)

Notes

I am aware that the whole idea is not particularly very TheGoWay™, but it is useful as a learning exercise, and it is useful for moving fast and optimising later.

About

Helpfully Functional Go - A useful collection of Go utilities. Designed for programmer happiness.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages