{"id":30055456,"url":"https://github.com/juliacollections/collects.jl","last_synced_at":"2026-02-14T19:05:34.144Z","repository":{"id":295295952,"uuid":"989701561","full_name":"JuliaCollections/Collects.jl","owner":"JuliaCollections","description":"Collect the elements of a given collection into a collection of the given type. Generalizes `collect`! Implement for types you own!","archived":false,"fork":false,"pushed_at":"2025-06-15T12:47:42.000Z","size":55,"stargazers_count":19,"open_issues_count":4,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-31T16:49:41.033Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Julia","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/JuliaCollections.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,"zenodo":null}},"created_at":"2025-05-24T16:40:42.000Z","updated_at":"2025-07-21T21:22:06.000Z","dependencies_parsed_at":"2025-05-30T12:15:45.474Z","dependency_job_id":null,"html_url":"https://github.com/JuliaCollections/Collects.jl","commit_stats":null,"previous_names":["nsajko/collectas.jl","juliacollections/collects.jl"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/JuliaCollections/Collects.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaCollections%2FCollects.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaCollections%2FCollects.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaCollections%2FCollects.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaCollections%2FCollects.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JuliaCollections","download_url":"https://codeload.github.com/JuliaCollections/Collects.jl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaCollections%2FCollects.jl/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269331666,"owners_count":24399141,"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","status":"online","status_checked_at":"2025-08-07T02:00:09.698Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2025-08-07T21:50:09.651Z","updated_at":"2026-02-14T19:05:34.137Z","avatar_url":"https://github.com/JuliaCollections.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Collects\n\n[![Build Status](https://github.com/JuliaCollections/Collects.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/JuliaCollections/Collects.jl/actions/workflows/CI.yml?query=branch%3Amain)\n[![Coverage](https://codecov.io/gh/JuliaCollections/Collects.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaCollections/Collects.jl)\n[![Package version](https://juliahub.com/docs/General/Collects/stable/version.svg)](https://juliahub.com/ui/Packages/General/Collects)\n[![Package dependencies](https://juliahub.com/docs/General/Collects/stable/deps.svg)](https://juliahub.com/ui/Packages/General/Collects?t=2)\n[![PkgEval](https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/C/Collects.svg)](https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/C/Collects.html)\n[![Aqua](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl)\n\nA Julia package to collect the elements of a given collection into a collection of the given type. Generalizes the `collect` function from `Base`.\n\nExports:\n\n* `collect_as`, a function: the user-level interface\n\n* `Collect`, a type: the lower-level interface, meant primarily for adding methods for package authors\n\n* `EmptyIteratorHandling`, a module\n\n## Motivation\n\nThe motivation for creating this package is overcoming these issues of the `collect` interface:\n\n* The `collect` function allows the caller to specify the desired element type, but does not allow specifying the desired container type.\n\n    * The interface in this package allows the caller to specify the desired output type, not just the element type.\n\n    * This package implements the interface for several `Base` types and invites other packages to implement the interface for their own types.\n\n    * This is basically Julia issue [#36288](https://github.com/JuliaLang/julia/issues/36288) by Takafumi Arakaki.\n\n* The `collect` function may rely on type inference to determine the element type of the output type when the iterator is empty and the element type wasn't specified by the caller.\n\n    * This package lets the caller decide how the element type of an empty iterator is determined.\n\n        * By default, type inference is not used.\n\n        * By default, an `ArgumentError` is thrown in case a good element type can not be determined.\n\nThis package provides a better interface to replace `collect`.\n\n## Usage examples\n\nThe `collect_as` function takes two positional arguments:\n\n* the output type\n\n* an arbitrary iterator\n\nIt collects the elements of the iterator into a collection with the provided output type as the\ntype of the collection.\n\n```julia-repl\njulia\u003e it = Iterators.map((x -\u003e 0.5 * x), [2, 2, 3]);\n\njulia\u003e collect_as(Vector, it)\n3-element Vector{Float64}:\n 1.0\n 1.0\n 1.5\n\njulia\u003e collect_as(Vector{Float32}, it)\n3-element Vector{Float32}:\n 1.0\n 1.0\n 1.5\n\njulia\u003e collect_as(Set, it)\nSet{Float64} with 2 elements:\n  1.0\n  1.5\n\njulia\u003e collect_as(Set, [])\nERROR: ArgumentError: couldn't figure out an appropriate element type\n[...]\n\njulia\u003e collect_as(Set{Number}, [])\nSet{Number}()\n```\n\nThe behavior for an empty iterator when the element type is not known may be adjusted by passing a keyword argument:\n\n```julia-repl\njulia\u003e collect_as(Set, []; empty_iterator_handler = Returns(Union{}))\nSet{Union{}}()\n\njulia\u003e collect_as(Set, Iterators.map((x -\u003e 0.5 * x), 1:0); empty_iterator_handler = EmptyIteratorHandling.may_use_type_inference)\nSet{Float64}()\n```\n\nNB: behavior may depend on Julia implementation details when using `may_use_type_inference`.\n\nIt's also possible to collect into a collection with a dimensionality greater than one, assuming the shape can be inferred:\n\n```julia-repl\njulia\u003e collect_as(Matrix, Iterators.map(cos, rand(2, 2)))\n2×2 Matrix{Float64}:\n 0.792873  0.781535\n 0.553728  0.941229\n```\n\nThe `collect_as` function just forwards to the lower-level interface around `Collect`. The lower level interface is used like so:\n\n```julia-repl\njulia\u003e c = Collect(; empty_iterator_handler = EmptyIteratorHandling.just_throws);\n\njulia\u003e c(Vector, (3, 3.0))\n2-element Vector{Real}:\n 3\n 3.0\n```\n\n`collect_as` additionally allows being called with only one argument, like `collect_as(output_type)`. `collect_as(t)` behaves very similarly to `Base.Fix1(collect_as, t)`, basically it is a partial application of the function. Example:\n\n```julia-repl\njulia\u003e c = collect_as(Vector);\n\njulia\u003e m = c ∘ Iterators.map;\n\njulia\u003e m(sin, 0:3)\n4-element Vector{Float64}:\n 0.0\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n```\n\n## Implementations\n\nThis package implements the interface for some `Base` types, including:\n\n* `Set`\n\n* `Array`\n\n* `Memory` (when present, on Julia v1.11 and up)\n\n* `Tuple`\n\nThird-party packages are invited to add this package as a (weak or strong) dependency and implement the interface for their types. Some example packages that do this:\n\n* [FixedSizeArrays.jl](https://github.com/JuliaArrays/FixedSizeArrays.jl)\n\n## How to implement for your collection type\n\nTo implement the interface for one's own container type, say `Collection`, define a method like this:\n\n```julia\nfunction (c::Collect)(t::Type{\u003c:Collection}, iterator::Any)\n    ...\nend\n```\n\nIf `iterator` turns out empty, `eltype(iterator)` is neither the bottom type nor concrete, and `t` doesn't specify an element type, call `(c.empty_iterator_handler)(iterator)` to try to obtain the element type.\n\n## Rough specification\n\n### Identity\n\nIf `iterator isa output_type` already, a (shallow) copy of `iterator` must be returned.\n\n### Return type\n\nFor each `c`, `output_type` and `iterator` such that `c isa Collect`, if `c(output_type, iterator)` returns a value, the value must be of type `output_type`.\n\n### Element type of the output\n\nThe element type must be consistent with `output_type` (as already implied above).\n\nIf the output element type does not supertype the element type of `iterator`, the elements of `iterator` are converted into the output element type.\n\nRule for determining the element type of the output (when applicable, that is, when the output type depends on its element type, and the output type does not subtype `Tuple`):\n\n* If the element type is specified by `output_type`, it's the element type of the output.\n\n* Otherwise, if `iterator` is empty:\n\n    * If `isconcretetype(eltype(iterator)) || (eltype(iterator) \u003c: Union{})`, `eltype(iterator)` is the output element type.\n\n    * Otherwise, the output element type must be determined by `(c.empty_iterator_handler)(iterator)`.\n\n* Otherwise, the output element type is the `typejoin` of the types of the elements of `iterator`.\n\n### Shape of the output\n\nThe shape of the output must be consistent with `output_type` (as already implied above).\n\nTo the extent that the shape is not specified by `output_type`, it is inferred from `Base.IteratorSize(iterator)`.\n\n### Other rules for implementers to follow\n\nAny added method must take exactly two arguments.\n\n* If you disagree, open a feature request on Github to achieve agreement for adding to the interface.\n\nThe first argument of any added method must be constrained to be a type (of type `Type`).\n\nMake sure you own the constraint that is placed on the first argument. This is required even when you know you own the second argument.\n\n* The rationale for this rule is to prevent causing ambiguity for other packages.\n\n* For example, defining a method with a signature like here is *not* allowed, because you don't own `Vector`, even if you do own `A`:\n\n  ```julia\n  function (::Collect)(::Type{Vector}, ::A) end\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliacollections%2Fcollects.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuliacollections%2Fcollects.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliacollections%2Fcollects.jl/lists"}