{"id":13412904,"url":"https://github.com/BooleanCat/go-functional","last_synced_at":"2025-03-14T18:32:35.927Z","repository":{"id":37692381,"uuid":"124119818","full_name":"BooleanCat/go-functional","owner":"BooleanCat","description":"go-functional is a library of iterators to augment the standard library","archived":false,"fork":false,"pushed_at":"2024-10-28T13:15:00.000Z","size":3083,"stargazers_count":450,"open_issues_count":2,"forks_count":23,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-11-02T09:08:32.919Z","etag":null,"topics":["functional-programming","go","golang"],"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/BooleanCat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-06T18:17:44.000Z","updated_at":"2024-10-31T19:35:28.000Z","dependencies_parsed_at":"2022-07-16T16:30:29.275Z","dependency_job_id":"97621080-c201-4819-9098-aee8c66aea92","html_url":"https://github.com/BooleanCat/go-functional","commit_stats":null,"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BooleanCat%2Fgo-functional","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BooleanCat%2Fgo-functional/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BooleanCat%2Fgo-functional/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BooleanCat%2Fgo-functional/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BooleanCat","download_url":"https://codeload.github.com/BooleanCat/go-functional/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243625195,"owners_count":20321253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","golang"],"created_at":"2024-07-30T20:01:30.861Z","updated_at":"2025-03-14T18:32:35.919Z","avatar_url":"https://github.com/BooleanCat.png","language":"Go","readme":"# Functional Programming in Go\n\n[![GitHub release (with filter)](https://img.shields.io/github/v/release/BooleanCat/go-functional?sort=semver\u0026logo=Go\u0026color=%23007D9C\u0026include_prereleases)](https://github.com/BooleanCat/go-functional/releases)\n[![Actions Status](https://github.com/BooleanCat/go-functional/workflows/test/badge.svg)](https://github.com/BooleanCat/go-functional/actions)\n[![Go Reference](https://pkg.go.dev/badge/github.com/BooleanCat/go-functional/v2.svg)](https://pkg.go.dev/github.com/BooleanCat/go-functional/v2)\n[![Go Report Card](https://goreportcard.com/badge/github.com/BooleanCat/go-functional/v2)](https://goreportcard.com/report/github.com/BooleanCat/go-functional/v2)\n[![codecov](https://codecov.io/gh/BooleanCat/go-functional/branch/main/graph/badge.svg?token=N2E43RSR14)](https://codecov.io/gh/BooleanCat/go-functional)\n\nA library of iterators for use with [iter.Seq](https://pkg.go.dev/iter#Seq). Requires Go 1.23+.\n\n```go\n// The first 5 natural numbers\nnumbers := slices.Collect(\n\tit.Take(it.NaturalNumbers[int](), 5),\n)\n\n// All even numbers\nevens := it.Filter(it.NaturalNumbers[int](), filter.IsEven)\n\n// String representations of integers\nnumbers := it.Map(it.NaturalNumbers[int](), strconv.Itoa)\n```\n\n_[Reference documentation](https://pkg.go.dev/github.com/BooleanCat/go-functional/v2)_\n\n\u003cpicture\u003e\n\t\u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"assets/banner_dark.png\" /\u003e\n\t\u003csource media=\"(prefers-color-scheme: light)\" srcset=\"assets/banner_light.png\" /\u003e\n\t\u003cimg alt=\"go-functional gopher banner image\" src=\"assets/banner_light.png\" /\u003e\n\u003c/picture\u003e\n\n## Installation\n\n```terminal\ngo get github.com/BooleanCat/go-functional/v2@latest\n```\n\n## Overview\n\nMost functions offered by this package are either consumers or iterators.\n\n[Consumers](#consumers) will iterate over an iterator and completely or partially drain them of\nvalues and (in most cases) collect the values into a data type.\n\n[Iterators](#iterators) are functions that yield new values and can be ranged over. See Go's\ndocumentation for iterators for more details.\n\n## Consumers\n\nThe standard libary provides functions to collect iterators in the\n[slices](https://pkg.go.dev/slices) and [maps](https://pkg.go.dev/maps) packages that should satisfy\nmost cases where collection is needed.\n\nThis package provides additional collection methods and makes existing consumers from the standard\nlibrary chainable.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e Attempting to collect infinite iterators will cause an infinite loop and likely deadlock. Consider\n\u003e bounding infinite iterators before collect (for example using [Take](#take)).\n\n### All \u0026 Any\n\n`All` will return `true` if all values yielded by an iterator are `true`, or `false` otherwise.\nIteration will terminate early if `false` is encountered. Empty iterators will return `true`.\n\n```go\nit.All(slices.Values([]bool{true, false, true}))  // false\n```\n\n`Any` will return `true` if any value yielded by an iterator is `true`, or `false` otherwise.\nIteration will terminate early if `true` is encountered. Empty iterators will return `false`.\n\n```go\nit.Any(slices.Values([]bool{false, false, true}))  // true\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `All` or `Any` due to limitations with Go's type system.\n\n### Collect\n\nIn most cases [slices.Collect](https://pkg.go.dev/slices#Collect) from the standard library may be\nused to collect items from an iterator into a slice. There are several other variants of collect\navailable for use for different use cases.\n\n```go\n// Chainable\nnumbers := itx.NaturalNumbers[int]().Take(5).Collect()\n\n// Collect an iter.Seq2[V, W] into two slices\nkeys, values := it.Collect2(maps.All(map[string]int{\"one\": 1, \"two\": 2}))\n\n// As above, but chainable\nkeys, values := itx.FromMap(map[string]int{\"one\": 1, \"two\": 2}).Collect()\n```\n\n\u003ch3 id=\"trycollect\"\u003eTryCollect \u0026 MustCollect\u003c/h3\u003e\n\nDealing with iterators that return `T, error` can involve the boilerplate of checking that the\nreturned slice of errors only contains `nil`. `TryCollect` solves this by collecting all values into\na slice and returning a single error: the first one encountered.\n\n```go\ntext := strings.NewReader(\"one\\ntwo\\nthree\\n\")\n\nif lines, err := it.TryCollect(it.LinesString(text)); err != nil {\n\tfmt.Println(lines)\n}\n```\n\n`MustCollect` is similar except that if an error is encountered then a panic will occur.\n\n```go\ntext := strings.NewReader(\"one\\ntwo\\nthree\\n\")\n\nlines := it.MustCollect(it.LinesString(text))\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e Use `MustCollect` when you can guarantee that no error will occur (such as with\n\u003e [strings.Reader](https://pkg.go.dev/strings#Reader)).\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e If an error is encountered, collection stops. This means the iterator being collected may not be\n\u003e fully drained.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `TryCollect` or `MustCollect` due to limitations with Go's type\n\u003e system.\n\n### ForEach\n\nForEach consumes an iterator and applies a function to each value yielded.\n\n```go\nit.ForEach(slices.Values([]int{1, 2, 3}), func(number int) {\n\tfmt.Println(number)\n})\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3}).ForEach(func(number int) {\n\tfmt.Println(number)\n})\n\n// For each member of an iter.Seq2\nit.ForEach2(slices.All([]int{1, 2, 3}), func(index int, number int) {\n\tfmt.Println(index, number)\n})\n\n// As above, but chainable\nitx.FromSlice([]int{1, 2, 3}).Enumerate().ForEach(func(index int, number int) {\n\tfmt.Println(index, number)\n})\n```\n\n### Fold\n\nFold every element into an accumulator by applying a function and passing an initial value.\n\n```go\nit.Fold(slices.Values([]int{1, 2, 3}), op.Add, 0)\n\n// Fold an iter.Seq2\nit.Fold2(slices.All([]int{1, 2, 3}), func(i, a, b int) int {\n\treturn i + 1\n}, 0)\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e The [op package](it/op/op.go) contains some simple, pre-defined operation functions.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `Fold` due to limitations with Go's type system.\n\n### Max \u0026 Min\n\n`Max` and `Min` consume an iterator and return the maximum or minimum value yielded and true if the\niterator contained at least one value, or the zero value and false if the iterator was empty.\n\nThe type of the value yielded by the iterator must be `comparable`.\n\n```go\nmax, ok := it.Max(slices.Values([]int{1, 2, 3}))\nmin, ok := it.Min(slices.Values([]int{1, 2, 3}))\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `Max` or `Min` due to limitations with Go's type system.\n\n### Len\n\nLen consumes an iterator and returns the number of values yielded.\n\n```go\nit.Len(slices.Values([]int{1, 2, 3}))\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3}).Len()\n\n// Len of an iter.Seq2\nit.Len2(slices.All([]int{1, 2, 3}))\n\n// As above, but chainable\nitx.FromSlice([]int{1, 2, 3}).Enumerate().Len()\n```\n\n### Find\n\nFind consumes an iterator until a value is found that satisfies a predicate. It returns the value\nand true if one was found, or the zero value and false if the iterator was exhausted before a value\nwas found.\n\n```go\nfound, ok := it.Find(slices.Values([]int{1, 2, 3}), func(i int) bool {\n\treturn i == 2\n})\n\n// Chainable\nvalue, ok := itx.FromSlice([]int{1, 2, 3}).Find(func(number int) bool {\n\treturn number == 2\n})\n\n// Finding within an iter.Seq2\nindex, value, ok := it.Find2(slices.All([]int{1, 2, 3}), func(i, v int) bool {\n\treturn i == 2\n})\n\n// As above, but chainable\nindex, value, ok := itx.FromSlice([]int{1, 2, 3}).Enumerate().Find(func(index int, number int) bool {\n\treturn index == 1\n})\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e The [filter package](it/filter/filter.go) contains some simple, pre-defined predicate functions.\n\n### Contains\n\nContains consumes an iterator until the provided value is found, returning true if the value was\nfound or false if the iterator was exhausted.\n\n```go\nok := it.Contains(slices.Values([]int{1, 2, 3}), 2)\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `Contains` due to limitations with Go's type system.\n\n### From, FromSlice, FromMap \u0026 Seq\n\nThe itx package contains some helper functions to convert iterators, slices or maps directly into\nchainable iterators to avoid some boilerplate.\n\n```go\nitx.From(slices.Values([]int{1, 2, 3})).Collect()\n\nitx.From2(maps.All(map[int]string{1: \"one\"}))\n\nitx.FromSlice([]int{1, 2, 3}).Collect()\n\nitx.FromMap(map[int]int{1: 2}).Collect()\n```\n\nThe `itx` package also contains a helper function Seq that will convert a chainable iterator into an\n[iter.Seq](https://pkg.go.dev/iter#Seq) so that it can be used in functions that accept that type\n(such as the standard library).\n\nThe standard library functions that work with iterators (such as\n[slices.Collect](https://pkg.go.dev/slices#Collect)) accept the\n[iter.Seq](https://pkg.go.dev/iter#Seq) family of types. This precludes those functions from\naccepting types with another alias (such as `itx.Iterator`) with the same type definition. This\nmeans it is necessary to \"covert\" an `itx.Iterator` into an [iter.Seq](https://pkg.go.dev/iter#Seq)\nbefore passing the iterator into those functions.\n\n```go\nslices.Collect(itx.NaturalNumbers[int]().Take(3).Seq())\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e go-functional's functions that accept iterators always accept `func(func(V) bool)` or\n\u003e `func(func(V, W) bool)` rather than any specific type alias so that they can accept any type alias\n\u003e with the definitions [iter.Seq](https://pkg.go.dev/iter#Seq),\n\u003e [iter.Seq2](https://pkg.go.dev/iter#Seq2), `itx.Iterator`, `itx.Iterator2` or any other\n\u003e third-party types aliased to the same type.\n\n### ToChannel\n\nToChannel sends yielded values to a channel.\n\nThe channel is closed when the iterator is exhausted. Beware of leaked go routines when using this\nfunction with an infinite iterator.\n\n```go\nchannel := it.ToChannel(slices.Values([]int{1, 2, 3}))\n\nfor number := range channel {\n\tfmt.Println(number)\n}\n\n// Chainable\nchannel := itx.FromSlice([]int{1, 2, 3}).ToChannel()\n\nfor number := range channel {\n\tfmt.Println(number)\n}\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e Unlike most consumers, the iterator is not immediately consumed by ToChannel. Instead is it\n\u003e consumed as values are pulled from the channel.\n\n### Drain\n\nDrain consumes an iterator's values and drops them.\n\n```go\nprintValue := func(n int) int {\n\tfmt.Println(n)\n\treturn n\n}\n\nit.Drain(it.Map(slices.Values([]int{1, 2, 3}), printValue))\n\n// Chainable\nitx.From(it.Map(slices.Values([]int{1, 2, 3}), printValue)).Drain()\n\n// Drain an iter.Seq2\nprintValue2 := func(i, n int) (int, int) {\n\tfmt.Println(n)\n\treturn i, n\n}\n\nit.Drain2(it.Map2(slices.All([]int{1, 2, 3}), printValue2))\n\n// As above, but chainable\nitx.From2(it.Map2(slices.All([]int{1, 2, 3}), printValue2)).Drain()\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e Use `Drain` to consume an iterator to invoke any side effects when you don't need to collect the\n\u003e values.\n\n## Iterators\n\nThis library contains two kinds of iterators in the `it` and `itx` packages. In most cases you'll\nfind the same iterators in each package, the difference between them being that the iterators in the\n`itx` package can be \"dot-chained\" (e.g. `iter.Filter(...).Take(3).Collect()`) and those in `it`\ncannot.\n\nIterators within the `it` package are of the type [iter.Seq](https://pkg.go.dev/iter#Seq) or\n[iter.Seq2](https://pkg.go.dev/iter#Seq2) (from the standard library). Iterators within the `itx`\npackage are of the type `itx.Iterator[V]` or `itx.Iterator2[V, W]`.\n\nThere are two important factors to consider when using iterators:\n\n1. Some iterators yield an infinite number of values and care should be taken to avoid consuming\n   (using functions such as [slices.Collect](https://pkg.go.dev/slices#Collect)) otherwise it's\n   likely to cause an infinite while loop.\n2. Many iterators take another iterator as an argument (such as [Filter](#filter) or Map). Avoid\n   using an iterator after it has been passed to another iterator otherwise you'll risk multiple\n   functions consuming a single (likely not thread-safe) iterator and causing confusing and\n   difficult to debug behaviour.\n\n### Chain\n\nChain yields values from multiple iterators in the sequence they are provided in. Think of it as\nglueing many iterators together.\n\nWhen provided zero iterators it will behave like [Exhausted](#exhausted).\n\n```go\nnumbers := it.Chain(slices.Values([]int{1, 2}), slices.Values([]int{3, 4}))\n\npairs := itx.FromSlice([]int{1, 2}).Chain(slices.Values([]int{3, 4}))\n\npairs := it.Chain2(maps.All(map[string]int{\"a\": 1}), maps.All(map[string]int{\"b\": 2}))\n\npairs := itx.FromMap(map[string]int{\"a\": 1}).Chain(maps.All(map[string]int{\"b\": 2}))\n```\n\n### FromChannel\n\nFromChannel pulls values from a channel and yields them via an iterator. The usual concerns around\nchannel deadlocks apply here.\n\nThe iterator is exhausted when the channel is closed and it is the responsibility of the caller to\nclose the channel.\n\n```go\nitems := make(chan int)\n\ngo func() {\n\tdefer close(items)\n\titems \u003c- 1\n\titems \u003c- 2\n}()\n\nfor number := range it.FromChannel(items) {\n\tfmt.Println(number)\n}\n\n// Chainable\nitems := make(chan int)\n\ngo func() {\n\tdefer close(items)\n\titems \u003c- 1\n\titems \u003c- 0\n}()\n\nfor number := range itx.FromChannel(items).Exclude(filter.IsZero) {\n\tfmt.Println(number)\n}\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e In order to prevent a deadlock, the channel must be closed before attemping to stop the iterator\n\u003e when it's used in a pull style. See [iter.Pull](https://pkg.go.dev/iter#Pull).\n\n### Compact\n\nCompact yields all values from a delegate iterator that are not zero values. It is functionally\nequivalent to `it.Exclude(delegate, filter.IsZero)`.\n\n```go\nwords := it.Compact(slices.Values([]string{\"foo\", \"\", \"bar\", \"\", \"\"}))\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `Compact` due to limitations with Go's type system.\n\n### Cycle\n\nCycle yields all values from an iterator before returning to the beginning and yielding all values\nagain (indefinitely).\n\n```go\nnumbers := it.Take(it.Cycle(slices.Values([]int{1, 2})), 5)\n\n// Chainable\nnumbers := itx.FromSlice([]int{1, 2}).Cycle().Take(5)\n\n// Cycling an iter.Seq2\nnumbers := it.Take2(it.Cycle2(maps.All(map[int]string{1: \"one\"})), 5)\n\n// As above, but chainable\nnumbers := itx.FromMap(map[int]string{1: \"one\"}).Cycle().Take(5)\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e Since cycle needs to store all values yielded in memory, its memory usage will grow as the first\n\u003e cycle is consumed and remain at a constant size on subsequent cycles.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e This iterator yields an infinite number of values and care should be taken when consuming it\n\u003e otherwise it's likely to result in an infinite while loop. Consider bounding the size of the\n\u003e iterator before consuming (e.g. using [Take](#take)).\n\n\u003ch3 id=\"drop\"\u003eDrop \u0026 DropWhile\u003c/h3\u003e\n\nDrop yields all values from a delegate iterator after dropping a number of values from the\nbeginning. Values are not dropped immediately, but when consumption begins.\n\nWhen dropping a number of values larger than the length of the iterator, it behaves like\n[Exhausted](#exhausted).\n\n```go\nnumbers := it.Drop(slices.Values([]int{1, 2, 3, 4, 5}), 2)\n\n// Chainable\nnumbers := itx.FromSlice([]int{1, 2, 3, 4, 5}).Drop(2)\n\n// Dropping on iter.Seq2\nnumbers := it.Drop2(maps.All(map[int]string{1: \"one\", 2: \"two\", 3: \"three\"}), 1)\n\n// As above, but chainable\nnumbers := itx.FromMap(map[int]string{1: \"one\", 2: \"two\", 3: \"three\"}).Drop(1)\n```\n\nDropWhile drops values from the provided iterator whilst the predicate returns true for each value.\nAfter the first value results in the predicate returning false, the iterator resumes as normal.\n\n```go\nslices.Collect(it.DropWhile(slices.Values([]int{1, 2, 3, 4, 5}), filter.LessThan(3)))\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3, 4, 5}).DropWhile(filter.LessThan(3)).Collect()\n\nlessThanThree := func(string, number int) { return number \u003c 3 }\n\n// Taking from iter.Seq2\nmaps.Collect(it.DropWhile2(maps.All(map[string]int{\"one\": 1, \"four\": 4}), lessThanThree))\n\n// As above, but chainable\nitx.FromMap(map[string]int{\"one\": 1, \"four\": 4}).DropWhile(lessThanThree).Collect()\n```\n\n### Enumerate\n\nEnumerating an [iter.Seq](https://pkg.go.dev/iter#Seq) like iterator returns an\n[iter.Seq2](https://pkg.go.dev/iter#Seq2) like iterator yielding the index of each value and the\nvalue.\n\n```go\nindexedValues := it.Enumerate(slices.Values([]int{1, 2, 3}))\n\n// Chainable\nindexedValues := itx.FromSlice([]int{1, 2, 3}).Enumerate()\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e When iterating over a slice and immediately enumerating, consider instead using the standard\n\u003e library's [slices.All](https://pkg.go.dev/slices#All) function rather than this.\n\n### Exhausted\n\nExhausted is an iterator that yields no values.\n\n```go\nslices.Collect(it.Exhausted[int]())\n\n// Chainable\nit.Exhausted[int]().Collect()\n\n// Exhausted iter.Seq2\nmaps.Collect(it.Exhausted2[int, string]())\n\n// As above, but chainable\nitx.Exhausted2[int, string]().Collect()\n```\n\n\u003ch3 id=\"filter\"\u003eFilter \u0026 Exclude\u003c/h3\u003e\n\nFilter yields values from an iterator that satisfy a predicate. Likewise, exclude yields values from\nan iterator that do not satisfy a predicate.\n\n```go\nit.Filter(slices.Values([]int{1, 2, 3, 4, 5}), filter.IsEven)\nit.Exclude(slices.Values([]int{1, 2, 3, 4, 5}), filter.IsEven)\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3, 4, 5}).Filter(filter.IsEven)\nitx.FromSlice([]int{1, 2, 3, 4, 5}).Exclude(filter.IsEven)\n\n// Filtering an iter.Seq2\nisOne := func(n int, _ string) bool { return n == 1 }\n\nit.Filter2(maps.All(map[int]string{1: \"one\", 2: \"two\", 3: \"three\"}), isOne)\nit.Exclude2(maps.All(map[int]string{1: \"one\", 2: \"two\", 3: \"three\"}), isOne)\n\n// As above, but chainable\nitx.FromMap(map[int]string{1: \"one\", 2: \"two\", 3: \"three\"}).Filter(isOne)\nitx.FromMap(map[int]string{1: \"one\", 2: \"two\", 3: \"three\"}).Exclude(isOne)\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e The [filter package](it/filter/filter.go) contains some simple, pre-defined predicate functions.\n\n### FilterError \u0026 ExcludeError\n\nSimilar to [Filter and Exclude](#filter), these functions filter values from an iterator using a\npredicate that may return an error.\n\n```go\nisFoo := func(s string) (bool, error) { return s == \"foo\", nil }\n\nvalues, err := it.TryCollect(it.FilterError(slices.Values([]string{\"foo\", \"bar\"}), isFoo))\nvalues, err := it.TryCollect(it.ExcludeError(slices.Values([]string{\"foo\", \"bar\"}), isFoo))\n\n// Chainable\nvalues, err := it.TryCollect(itx.FromSlice([]int{\"foo\", \"bar\"}).FilterError(isFoo))\nvalues, err := it.TryCollect(itx.FromSlice([]int{\"foo\", \"bar\"}).ExcludeError(isFoo))\n```\n\n### FilterUnique\n\nFilterUnique yields only the unique values from an iterator.\n\n```go\nvalues := it.FilterUnique(slices.Values([]int{1, 2, 2, 3, 3, 3, 4}))\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e Unique values are stored in memory until the iterator is exhausted. Large iterators with\n\u003e many unique values may use a large amount of memory.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `FilterUnique` due to limitations with Go's type system.\n\n### Integers\n\nIntegers yields all integers in the range [start, stop) with the given step.\n\n```go\nfor i := range it.Integers[uint](0, 3, 1) {\n\tfmt.Println(i)\n}\n\n// Chainable\nfor i := range itx.Integers[uint](0, 3, 1).Drop(1) {\n\tfmt.Println(i)\n}\n```\n\n### Lines \u0026 LinesString\n\nLines yields lines from an [io.Reader](https://pkg.go.dev/io#Reader). Lines are split using the\nstandard library's [bufio.Scanner](https://pkg.go.dev/bufio#Scanner). Each value yielded from the\niterator is a line from the provided reader. Empty lines will result in empty values.\n\nSince reading from an [io.Reader](https://pkg.go.dev/io#Reader) can fail, each line is returned with\na corresponding `error` value.\n\nLinesString behaves exactly like Lines except that its values are strings rather than byte slices.\n\n```go\nbuffer := strings.NewReader(\"one\\ntwo\\nthree\\n\")\n\nfor line, err := range it.Lines(buffer) {\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tbreak\n\t}\n\n\tfmt.Println(string(line))\n}\n\nfor line, err := range it.LinesString(buffer) {\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tbreak\n\t}\n\n\tfmt.Println(line)\n}\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e Consider using [TryCollect](#trycollect) in conjunction with Lines to make error collection less\n\u003e cumbersome:\n\u003e\n\u003e ```go\n\u003e lines, err := it.TryCollect(it.LinesString(buffer))\n\u003e ```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e For cases where errors will never result from reading, such as with\n\u003e [bytes.Buffer](https://pkg.go.dev/bytes#Buffer), consider dropping the error value before\n\u003e collection:\n\u003e\n\u003e ```go\n\u003e lines := itx.LinesString(buffer).Left().Collect()\n\u003e ```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e As with [bufio.Scanner](https://pkg.go.dev/bufio#Scanner), there is a maximum line length per line\n\u003e of 65536 characters.\n\n\u003ch3 id=\"map\"\u003eMap \u0026 Transform\u003c/h3\n\nMap yields values from an iterator that have had the provided function applied to each value.\nTransform serves the same purpose but contrains the return type to the type of the iterator's values\n(see note below).\n\n```go\ndouble := func(n int) int { return n * 2 }\n\nit.Map(slices.Values([]int{1, 2, 3}), double)\n\n// Map for iter.Seq2\ndoubleBoth := func(n, m int) (int, int) { return n * 2, m * 2 }\n\nit.Map2(maps.All(map[int]int{1: 2, 3: 4}), doubleBoth)\n\n// Limited chainable flavour of Map\nitx.FromSlice([]int{0, 1, 2}).Transform(double)\n\n// As above for iter.Seq2\nitx.FromMap(map[int]int{1: 2}).Transform(doubleBoth)\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `Map` due to limitations with Go's type system. Instead a\n\u003e limited from of `Map` called `Transform` is provided where the type returned from operations is\n\u003e the same as a type of the iterator's values.\n\u003e\n\u003e A chainable Map will be added should Go's type system ever support new generic type parameters on\n\u003e methods.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e If you wish to chain operations on `Map`, you can do so by first converting it to an\n\u003e `itx.Iterator` like so:\n\u003e\n\u003e ```go\n\u003e itx.From(it.Map(slices.Values([]int{1, 2, 3}), double)).Collect()\n\u003e ```\n\n### MapError \u0026 TransformError\n\n`MapError` and `TransformError` behave like [Map and Transform](#map) except that they accept a\nfunction that may return an error.\n\n```go\ndouble := func(n int, err error) int { return n * 2, nil }\n\nit.MapError(slices.Values([]int{1, 2, 3}), double)\n\n// Limited chainable flavour of MapError\nitx.FromSlice([]int{1, 2, 3}).TransformError(double)\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `MapError` due to limitations with Go's type system. Instead a\n\u003e limited from of `MapError` called `TransformError` is provided where the type returned from\n\u003e operations is the same as a type of the iterator's values.\n\u003e\n\u003e A chainable MapError will be added should Go's type system ever support new generic type\n\u003e parameters on methods.\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e If you wish to chain operations on `MapError`, you can do so by first converting it to an\n\u003e `itx.Iterator2` like so:\n\u003e\n\u003e ```go\n\u003e itx.From2(it.MapError(slices.Values([]int{1, 2, 3}), double)).Collect()\n\u003e ```\n\n### NaturalNumbers\n\nNaturalNumbers yields all non-negative integers in ascending order.\n\n```go\nfor i := range it.Take(it.NaturalNumbers[int](), 3) {\n\tfmt.Println(i)\n}\n\n// Chainable\nfor i := range itx.NaturalNumbers[int]().Take(3) {\n\tfmt.Println(i)\n}\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e This iterator yields an infinite number of values and care should be taken when consuming it\n\u003e otherwise it's likely to result in an infinite while loop. Consider bounding the size of the\n\u003e iterator before consuming (e.g. using [Take](#take)).\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e There is no protection against overflowing whatever integer type is used for this iterator.\n\n### Once\n\nOnce yields the provided value once before being exhausted.\n\n```go\nslices.Collect(it.Once(42))\n\n// Chainable\nitx.Once(42).Collect()\n\n// For iter.Seq2\nmaps.Collect(it.Once2(42, \"42\"))\n\n// As above, but chainable\nitx.Once(42, \"42\").Collect()\n```\n\n### Repeat\n\nRepeat yields the same value indefinitely.\n\n```go\nslices.Collect(it.Take(it.Repeat(42), 5))\n\n// Chainable\nitx.Repeat(42).Take(5).Collect()\n\n// For iter.Seq2\nmaps.Collect(it.Take2(it.Repeat(42, \"42\"), 5))\n\n// As above, but chainable\nitx.Repeat2(42, \"42\").Take(5).Collect()\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!WARNING]\n\u003e This iterator yields an infinite number of values and care should be taken when consuming it\n\u003e otherwise it's likely to result in an infinite while loop. Consider bounding the size of the\n\u003e iterator before consuming (e.g. using [Take](#take)).\n\n\u003ch3 id=\"take\"\u003eTake \u0026 TakeWhile\u003c/h3\u003e\n\nTake limits the number of values of an iterator to a specified size. If the iterator has fewer\nvalues than the provided number then it behaves as though the original iterator is not changed.\n\n```go\nslices.Collect(it.Take(slices.Values([]int{1, 2, 3}), 2))\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3}).Take(2).Collect()\n\n// Taking from iter.Seq2\nmaps.Collect(it.Take2(slices.All([]int{1, 2, 3}), 2))\n\n// As above, but chainable\nitx.FromSlice([]int{1, 2, 3}).Enumerate().Take(2).Collect()\n```\n\nTakeWhile yields values from the provided iterator whilst the predicate returns true for each value.\nAfter the first value results in the predicate returning false, the iterator is exhausted.\n\n```go\nslices.Collect(it.TakeWhile(slices.Values([]int{1, 2, 3}), filter.LessThan(3)))\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3}).TakeWhile(filter.LessThan(3)).Collect()\n\nlessThanThree := func(string, number int) { return number \u003c 3 }\n\n// Taking from iter.Seq2\nmaps.Collect(it.TakeWhile2(maps.All(map[string]int{\"one\": 1, \"four\": 4}), lessThanThree))\n\n// As above, but chainable\nitx.FromMap(map[string]int{\"one\": 1, \"four\": 4}).TakeWhile(lessThanThree).Collect()\n```\n\n### Zip, Left \u0026 Right\n\n`Zip` yields pairs of values from two iterators. It is exhausted when one of the two provided\niterators is exhausted.\n\n```go\nnumbers := []int{1, 2, 3}\nstrings := []string{\"one\", \"two\", \"three\"}\n\nmaps.Collect(it.Zip(slices.Values(numbers), slices.Values(strings)))\n```\n\n`Left` and `Right` are functions that discard the left or right values of an\n[iter.Seq2](https://pkg.go.dev/iter#Seq2).\n\n```go\nslices.Collect(it.Left(slices.All([]int{1, 2, 3})))\nslices.Collect(it.Right(slices.All([]int{1, 2, 3})))\n\n// Chainable\nitx.FromSlice([]int{1, 2, 3}).Enumerate().Left().Collect()\nitx.FromSlice([]int{1, 2, 3}).Enumerate().Right().Collect()\n```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!TIP]\n\u003e A common pattern when working with `Zip` iterators in other languages is to fill excess values\n\u003e with some constant value. This pattern can easily to replicated here by using [Chain](#chain) and\n\u003e [Repeat](#repeat):\n\u003e\n\u003e ```go\n\u003e numbers := itx.FromSlice([]int{1, 2, 3, 4})\n\u003e strings := itx.FromSlice([]string{\"one\", \"two\"})\n\u003e\n\u003e it.Zip(numbers, strings.Chain(it.Repeat(\"missing\")))\n\u003e ```\n\n\u003c!-- prettier-ignore --\u003e\n\u003e [!NOTE]\n\u003e The `itx` package does not contain `Zip` due to limitations with Go's type system.\n\n## Attributions\n\nIn addition to those listed as code contributors on this repository, I'd like to also thank:\n\n- [**_Henry Wong_**](https://www.behance.net/henrywong) for designing the banner images and\n  stickers.\n","funding_links":[],"categories":["Functional","Go","方法","\u003ca name=\"Go\"\u003e\u003c/a\u003eGo"],"sub_categories":["Search and Analytic Databases","检索及分析资料库"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBooleanCat%2Fgo-functional","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBooleanCat%2Fgo-functional","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBooleanCat%2Fgo-functional/lists"}