{"id":43634320,"url":"https://github.com/rprtr258/fun","last_synced_at":"2026-02-04T17:13:11.998Z","repository":{"id":41484093,"uuid":"507402179","full_name":"rprtr258/fun","owner":"rprtr258","description":"functional and iterators routines","archived":false,"fork":false,"pushed_at":"2025-01-30T04:49:20.000Z","size":150,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-30T05:25:21.497Z","etag":null,"topics":["functional-programming","go","lodash"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rprtr258.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-25T19:39:37.000Z","updated_at":"2025-01-30T04:49:09.000Z","dependencies_parsed_at":"2023-10-14T20:45:24.243Z","dependency_job_id":"0a0d06b1-2ed9-4a5b-81e1-c0da1af7d428","html_url":"https://github.com/rprtr258/fun","commit_stats":null,"previous_names":["rprtr258/fun","rprtr258/go-flow"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/rprtr258/fun","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rprtr258%2Ffun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rprtr258%2Ffun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rprtr258%2Ffun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rprtr258%2Ffun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rprtr258","download_url":"https://codeload.github.com/rprtr258/fun/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rprtr258%2Ffun/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29091329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-04T03:31:03.593Z","status":"ssl_error","status_checked_at":"2026-02-04T03:29:50.742Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","go","lodash"],"created_at":"2026-02-04T17:13:11.770Z","updated_at":"2026-02-04T17:13:11.990Z","avatar_url":"https://github.com/rprtr258.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Iterator and functional utilities\n\nThe design is inspired by [samber/lo](https://github.com/samber/lo) and [iterator proposal](https://github.com/golang/go/issues/61897). This library does not deal with channel/pipes/concurrency as that is beyond the scope of this project.\n\n## Root package\nRoot package `github.com/rprtr258/fun` provides common slice and functional utilities.\n\n### Core types\n\n```go\n// Pair is a data structure that has two values.\ntype Pair[K, V any] struct {K K; V V}\n\n// Option is either value or nothing.\ntype Option[T any] struct {Value T; Valid bool}\n\n// Result is either value or error.\ntype Result[T any] Pair[T, error]\n```\n\n### Core constraints\n```go\n// RealNumber is a generic number interface that covers all Go real number types.\ntype RealNumber interface {\n\tint | int8 | int16 | int32 | int64 |\n\t\tuint | uint8 | uint16 | uint32 | uint64 |\n\t\tfloat32 | float64\n}\n\n// Number is a generic number interface that covers all Go number types.\ntype Number interface {\n\tRealNumber | complex64 | complex128\n}\n```\n\n### Design decisions\nDeclarations like\n```go\nfunc Map[R, T any, F interface {\n\tfunc(T) R | func(T, int) R\n}](f F, slice ...T) []R\n```\nexists for the reason that we want both `func(elem)` and `func(elem, index)` functions work. With such declaration Go cannot infer type `R`, so we have to specify it explicitly on usage: `fun.Map[string](fn, slice...)`\n\nAnother moment is that slice arguments are variadic. That allows user not to construct slice in some cases like `fun.Contains(status, \"OK\", \"Success\")` instead of `fun.Contains(status, []string{\"OK\", \"Success\"})`.\n\n### slice functions\n#### Map\nApplies function to all elements and returns slice with results.\n\n```go\nfun.Map(func(x int64, _ int) string {\n\treturn strconv.FormatInt(x, 10)\n}, 0, 1, 2)\n// []string{\"0\", \"1\", \"2\"}\n```\n\n#### Filter\nFilters slice elements using given predicate.\n\n```go\nfun.Filter(func(x int64, _ int) bool {\n\treturn x%2 == 0\n}, 0, 1, 2)\n// []int64{0, 2}\n```\n\n#### FilterMap\nTransform each element, leaving only those for which true is returned.\n\n```go\nfun.FilterMap(func(x int64, _ int) (string, bool) {\n\treturn strconv.FormatInt(x, 10), x%2 == 0\n}, 0, 1, 2)\n// []string{\"0\", \"2\"}\n```\n\n#### MapDict\nLike `Map` but uses dictionary instead of transform function.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.MapDict(dict, 0, 1, 2)\n// []string{\"zero\", \"one\", \"two\"}\n```\n\n#### MapErr\nLike `Map` but returns first error got from transform.\n\n```go\nfun.MapErr(func(x int64, _ int) (string, error) {\n\tif x%2 == 0 {\n\t\treturn strconv.FormatInt(x, 10), nil\n\t}\n\treturn \"\", errors.New(\"odd\")\n}, 0, 1, 2)\n// []string{\"0\"}, errors.New(\"odd\")\n```\n\n#### MapToSlice\nTransforms map to slice using transform function. Order is not guaranteed.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.MapToSlice(dict, func(k int, v string) string {\n\treturn fmt.Sprintf(\"%d: %s\", k, v)\n})\n// []string{\"0: zero\", \"1: one\", \"2: two\"}\n```\n\n#### MapFilterToSlice\nTransforms map to slice using transform function and returns only those for which true is returned. Order is not guaranteed.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.MapFilterToSlice(dict, func(k int, v string) (string, bool) {\n\treturn fmt.Sprintf(\"%d: %s\", k, v), k%2 == 0\n})\n// []string{\"0: zero\", \"2: two\"}\n```\n\n#### Keys\nReturns keys of map. Order is not guaranteed.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.Keys(dict)\n// []int{0, 1, 2}\n```\n\n#### Values\nReturns values of map. Order is not guaranteed.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.Values(dict)\n// []string{\"zero\", \"one\", \"two\"}\n```\n\n#### FindKeyBy\nReturns the key of the first element predicate returns truthy for.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.FindKeyBy(dict, func(k int, v string) bool {\n\treturn v == \"zero\"\n})\n// 0, true\n```\n\n#### Uniq\nReturns unique values of slice. In other words, removes duplicates.\n\n```go\nfun.Uniq(1, 2, 3, 1, 2)\n// []int{1, 2, 3}\n```\n\n#### Index\nReturns first found element by predicate along with it's index.\n\n```go\nfun.Index(func(s string, _ int) bool {\n\treturn strings.HasPrefix(s, \"o\")\n}, \"zero\", \"one\", \"two\")\n// \"one\", 1, true\n```\n\n#### Contains\nReturns true if an element is present in a collection.\n\n```go\nfun.Contains(\"zero\", \"zero\", \"one\", \"two\")\n// true\n```\n\n#### SliceToMap\nReturns a map containing key-value pairs provided by transform function applied to elements of the given slice.\n\n```go\nfun.SliceToMap(func(x int, _ int) (int, int) {\n\treturn x, x * 10\n}, 0, 1, 2)\n// map[int]int{0: 0, 1: 10, 2: 20}\n```\n\n#### FromMap\nReturns slice of key/value pairs from map.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.FromMap(dict)\n// []fun.Pair[int, string]{0: \"zero\", 1: \"one\", 2: \"two\"}\n```\n\n#### Copy\nReturns copy of slice.\n\n```go\nfun.Copy(1, 2, 3)\n// []int{1, 2, 3}\n```\n\n#### ReverseInplace\nReverses slice in place.\n\n```go\nxs := []int{1, 2, 3}\nfun.ReverseInplace(xs)\n// xs becomes []int{3, 2, 1}\n```\n\n#### Subslice\nReturns slice from start to end without panicking on out of bounds.\n\n```go\nxs := []int{1, 2, 3, 4, 5}\nfun.Subslice(1, 4, xs...)\n// []int{2, 3, 4}\n```\n\n#### Chunk\nDivides slice into chunks of size chunkSize.\n\n```go\nxs := []int{1, 2, 3, 4, 5}\nfun.Chunk(2, xs...)\n// [][]int{{1, 2}, {3, 4}, {5}}\n```\n\n#### ConcatMap\nLike `Map` but concatenates results.\n\n```go\nfun.ConcatMap(func(x int) []int {\n\treturn []int{x, x + 10, x + 100}\n}, 0, 1, 2)\n// []int{0, 10, 100, 1, 11, 101, 2, 12, 102}\n```\n\n#### All\nReturns true if all elements satisfy the condition.\n\n```go\nfun.All(func(x int) bool {\n\treturn x%2 == 0\n}, 0, 2, 4)\n// true\n```\n\n#### Any\nReturns true if any (at least one) element satisfies the condition.\n\n```go\nfun.Any(func(x int) bool {\n\treturn x%2 == 0\n}, 0, 1, 2)\n// true\n```\n\n#### SortBy\nSorts slice in place by given function.\n\n```go\nxs := []int{1, 2, 3, 4, 5}\nfun.SortBy(func(x int) int {\n\treturn -x\n}, xs)\n// xs becomes []int{5, 4, 3, 2, 1}\n```\n\n#### GroupBy\nGroups elements by key.\n\n```go\nfun.GroupBy(func(x int) int {\n\treturn x % 2\n}, 0, 1, 2, 3, 4)\n// map[int][]int{0: {0, 2, 4}, 1: {1, 3}}\n```\n\n### cmp\nUtilities utilizing values comparison.\n\n#### Min\nReturns the minimum of the given values.\n\n```go\nfun.Min(1, 2, 3)\n// 1\n```\n\n#### Max\nReturns the maximum of the given values.\n\n```go\nfun.Max(1, 2, 3)\n// 3\n```\n\n#### Clamp(x, low, high)\nReturns x clamped between low and high.\n\n```go\nfun.Clamp(99, 1, 10)\n// 10\n```\n\n#### MinBy\nReturns first minimum of given values using given order function.\n\n```go\nfun.MinBy(func(s string) int {\n\treturn len(s)\n}, \"one\", \"two\", \"three\")\n// \"one\"\n```\n\n#### MaxBy\nReturns first maximum of given values using given order function.\n\n```go\nfun.MaxBy(func(s string) int {\n\treturn len(s)\n}, \"one\", \"two\", \"three\")\n// \"three\"\n```\n\n### Working with Option type\n\n#### Invalid\nReturns empty Option.\n\n```go\nfun.Invalid[int]()\n// Option[int]{}\n```\n\n#### Valid\nReturns Option with given value.\n\n```go\nfun.Valid(1)\n// Option[int]{Value: 1, Valid: true}\n```\n\n#### Optional\nReturns Option with given value and validity.\n\n```go\nfun.Optional(1, true)\n// Option[int]{Value: 1, Valid: true}\n```\n\n#### FromPtr\nReturns Option with value from pointer.\n\n```go\nx := 1\nfun.FromPtr(\u0026x)\n// Option[int]{Value: 1, Valid: true}\nfun.FromPtr[int](nil)\n// Option[int]{}\n```\n\n#### Option.Unpack\nReturns value and validity.\n\n```go\nfun.Valid(1).Unpack()\n// (1, true)\n```\n\n#### Option.Or\nReturns first valid Option.\n\n```go\nfun.Valid(1).Or(fun.Invalid[int]())\n// Option[int]{Value: 1, Valid: true}\n```\n\n#### Option.OrDefault\nReturns value if Option is valid, otherwise returns default value.\n\n```go\nfun.Valid(1).OrDefault(0)\n// 1\n```\n\n#### Option.Ptr\nReturns pointer to value if Option is valid, otherwise returns nil.\n\n```go\nfun.Valid(1).Ptr()\n// \u0026[]int{1}[0]\n```\n\n#### OptMap\nReturns new Option with transformed value.\n\n```go\nfun.Valid(1).OptMap(func(x int) string {\n\treturn fmt.Sprintf(\"%d\", x)\n})\n// Option[string]{Value: \"1\", Valid: true}\n```\n\n#### OptFlatMap\nReturns new Option with transformed optional value.\n\n```go\nfun.Valid(1).OptFlatMap(func(x int) Option[string] {\n\treturn fun.Valid(fmt.Sprintf(\"%d\", x))\n})\n// Option[string]{Value: \"1\", Valid: true}\n```\n\n### fp\n\n#### Zero\nReturns zero value of given type.\n\n```go\nfun.Zero[int]()\n// 0\n```\n\n#### Debug\nPrints value and returns it. Useful for debug printing.\n\n```go\nfun.Debug(2+2)*2\n// prints 4\n```\n\n#### Has\nReturns true if map has such key.\n\n```go\ndict := map[int]string{\n\t0: \"zero\",\n\t1: \"one\",\n\t2: \"two\",\n}\nfun.Has(dict, 2)\n// true\n```\n\n#### Cond\nReturns first value for which true is returned.\n\n```go\nfun.Cond(\n\t1,\n\tfunc() (int, bool) { return 2, true },\n\tfunc() (int, bool) { return 3, false },\n)\n// 2\n```\n\n#### Ptr\nReturns pointer to value.\n\n```go\nfun.Ptr(1)\n// \u0026[]int{1}[0]\n```\n\n#### Deref\nReturns value from pointer. If pointer is nil returns zero value.\n\n```go\nfun.Deref[int](nil) // 0\nfun.Deref[int](new(int)) // 0\nx := 1\nfun.Deref[int](\u0026x) // 1\n```\n\n#### Pipe\nReturns value after applying endomorphisms. Endomorphism is just function from type to itself.\n\n```go\nfun.Pipe(\n\t\"hello  \",\n\tstrings.TrimSpace,\n\tstrings.NewReplacer(\"l\", \"|\").Replace,\n\tstrings.ToUpper,\n)\n// \"HE||O\"\n```\n\n#### If\nThere are multiple variations of `if` statement usable as expression.\n\n#### IF\nSimple ternary function.\n\n```go\nfun.IF(true, 1, 0)\n// 1\n```\n\n#### If, IfF\nReturns value from branch for which predicate is true. `F` suffix can be used to get values not evaluated immediately.\n\n```go\nfun.If(true, 1).Else(0)\n// 1\nfun.If(false, 1).ElseF(func() int { return 0 })\n// 0\nfun.If(false, 1).ElseIf(true, 2).Else(3)\n// 2\nfun.IfF(false, func() int { return 1 }).Else(0)\n// 0\n\nfun.If(true, db.Get(0)).Else(db.Get(1))\n// db.Get(0) result, db.Get called two times\nfun.IfF(true, func() Thing { return db.Get(0) }).ElseF(func() Thing { return db.Get(1) })\n// db.Get(0) result, db.Get called once\n```\n\n### Switch\n`switch` usable as expression.\n\n```go\nfun.Switch(\"one\", -1).\n\tCase(\"zero\", 0).\n\tCase(\"one\", 1).\n\tCase(\"two\", 2).\n\tEnd()\n// 1\n```\n\n## Iter\n\n`github.com/rprtr258/fun/iter` introduces iterator primitives for which `iter.Seq[T]` is basic.\n\n```go\ntype Seq[V any] func(yield func(V) bool)\n```\n\nWhich is a function which accepts function to `yield` values from iteration. `yield` must return `false` when iteration must stop (analogous to `break`).\n\nExample iterator yielding numbers from 1 to `n`, including `n`:\n\n```go\nfunc Range(n int) iter.Seq[int] {\n\treturn func(yield func(int) bool) {\n\t\tfor i := range n {\n\t\t\tif !yield(i) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n## Set\n\n`github.com/rprtr258/fun/set` introduces `Set[T]` primitive for collections of unique `comparable` values.\n\n## Ordered map\n\n`github.com/rprtr258/fun/orderedmap` introduces `OrderedMap[K, V]` data structure which acts like hashmap but also allows to iterate over keys in sorted order. Internally, binary search tree is used.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frprtr258%2Ffun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frprtr258%2Ffun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frprtr258%2Ffun/lists"}