{"id":13561128,"url":"https://github.com/sabiwara/aja","last_synced_at":"2025-10-23T22:01:43.142Z","repository":{"id":45818546,"uuid":"305045037","full_name":"sabiwara/aja","owner":"sabiwara","description":"Extension of the Elixir standard library focused on data stuctures, data manipulation and performance","archived":false,"fork":false,"pushed_at":"2025-01-15T11:55:31.000Z","size":2026,"stargazers_count":217,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-03T04:12:39.260Z","etag":null,"topics":["data-stuctures","elixir","ordered-map","persistent-vectors","util"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/sabiwara.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2020-10-18T07:18:42.000Z","updated_at":"2025-02-05T14:52:20.000Z","dependencies_parsed_at":"2023-12-23T08:22:14.950Z","dependency_job_id":"d288ce07-288b-43c7-95f0-a70acb36b8b9","html_url":"https://github.com/sabiwara/aja","commit_stats":{"total_commits":295,"total_committers":1,"mean_commits":295.0,"dds":0.0,"last_synced_commit":"ca99f8af929b0b70be5cbd367e2a32672f9a7cf9"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sabiwara%2Faja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sabiwara%2Faja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sabiwara%2Faja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sabiwara%2Faja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sabiwara","download_url":"https://codeload.github.com/sabiwara/aja/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248170165,"owners_count":21059144,"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":["data-stuctures","elixir","ordered-map","persistent-vectors","util"],"created_at":"2024-08-01T13:00:52.771Z","updated_at":"2025-10-23T22:01:42.929Z","avatar_url":"https://github.com/sabiwara.png","language":"Elixir","funding_links":[],"categories":["Algorithms and Data structures"],"sub_categories":[],"readme":"\u003cimg width=\"160\" src=\"https://raw.githubusercontent.com/sabiwara/aja/main/images/logo_large.png\" alt=\"Aja\"\u003e\n\n[![Hex Version](https://img.shields.io/hexpm/v/aja.svg)](https://hex.pm/packages/aja)\n[![docs](https://img.shields.io/badge/docs-hexpm-blue.svg)](https://hexdocs.pm/aja/)\n[![CI](https://github.com/sabiwara/aja/workflows/CI/badge.svg)](https://github.com/sabiwara/aja/actions?query=workflow%3ACI)\n\nExtension of the Elixir standard library focused on data stuctures, data\nmanipulation and performance.\n\n- [Data structures](#data-structures)\n- [Utility functions](#utility-functions)\n- [Installation](#installation)\n- [About Aja](#about-aja)\n- [FAQ](#faq)\n\n## Data structures\n\n\u003e \"there is one aspect of functional programming that no amount of cleverness on\n\u003e the part of the compiler writer is likely to mitigate — the use of inferior or\n\u003e inappropriate data structures.\" --\n\u003e [Chris Okasaki](https://www.cs.tufts.edu/~nr/cs257/archive/chris-okasaki/dissertation.pdf)\n\n#### Persistent vectors: `Aja.Vector`\n\nA blazing fast, pure Elixir implementation of a persistent vector, meant to\noffer an efficient alternative to lists. Supports many operations like appends\nand random access in effective constant time.\n\n```elixir\niex\u003e vector = Aja.Vector.new(1..10)\nvec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\niex\u003e Aja.Vector.append(vector, :foo)\nvec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, :foo])\niex\u003e vector[3]\n4\niex\u003e Aja.Vector.replace_at(vector, -1, :bar)\nvec([1, 2, 3, 4, 5, 6, 7, 8, 9, :bar])\niex\u003e 3 in vector\ntrue\n```\n\n`Aja.Vector` reimplements many of the functions from the `Enum` module\nspecifically for vectors, with efficiency in mind. It should be easier to use\nfrom Elixir than Erlang's [`:array`](https://erlang.org/doc/man/array.html)\nmodule and faster in most cases.\n\nThe `Aja.vec/1` and `Aja.vec_size/1` macros, while being totally optional, can\nmake it easier to work with vectors and make pattern-matching possible:\n\n```elixir\niex\u003e import Aja\niex\u003e vec([a, 2, c, _d, e]) = Aja.Vector.new(1..5); {a, c, e}\n{1, 3, 5}\niex\u003e vec(first ||| last) = Aja.Vector.new(1..1_000_000); {first, last}\n{1, 1000000}\niex\u003e match?(v when vec_size(v) \u003e 9, vec(1..10))\ntrue\n```\n\nThe `Aja.+++/2` operator provides synctactic sugar for vector concatenation:\n\n```elixir\niex\u003e vec([1, 2, 3]) +++ vec([4, 5])\nvec([1, 2, 3, 4, 5])\n```\n\n#### Ordered maps: `Aja.OrdMap`\n\nThe standard library does not offer any similar functionality:\n\n- regular maps do not keep track of the insertion order\n- keywords do but they only support atoms and do not have the right performance\n  characteristics (plain lists)\n\n```elixir\niex\u003e %{\"one\" =\u003e 1, \"two\" =\u003e 2, \"three\" =\u003e 3}\n%{\"one\" =\u003e 1, \"three\" =\u003e 3, \"two\" =\u003e 2}\niex\u003e ord_map = Aja.OrdMap.new([{\"one\", 1}, {\"two\", 2}, {\"three\", 3}])\nord(%{\"one\" =\u003e 1, \"two\" =\u003e 2, \"three\" =\u003e 3})\niex\u003e ord_map[\"two\"]\n2\niex\u003e Enum.to_list(ord_map)\n[{\"one\", 1}, {\"two\", 2}, {\"three\", 3}]\n```\n\nOrdered maps behave pretty much like regular maps, and the `Aja.OrdMap` module\noffers the same API as `Map`. The convenience macro `Aja.ord/1` make them a\nbreeze to instantiate or pattern-match upon:\n\n```elixir\niex\u003e import Aja\niex\u003e ord_map = ord(%{\"一\" =\u003e 1, \"二\" =\u003e 2, \"三\" =\u003e 3})\nord(%{\"一\" =\u003e 1, \"二\" =\u003e 2, \"三\" =\u003e 3})\niex\u003e ord(%{\"三\" =\u003e three, \"一\" =\u003e one}) = ord_map\niex\u003e {one, three}\n{1, 3}\n```\n\nAll data structures offer:\n\n- great performance characteristics at any size (see [FAQ](#faq))\n- well-documented APIs that are consistent with the standard library\n- implementation of `Inspect`, `Enumerable` and `Collectable` protocols\n- implementation of the `Access` behaviour\n- implementation of the `JSON.Encoder` protocol (on Elixir 1.18+)\n- (optional if `Jason` is installed) implemention of the `Jason.Encoder`\n  protocol\n\n#### Optimized `Enum`: `Aja.Enum`\n\n`Aja.Enum` mirrors the `Enum` module, but its implementation is highly optimized\nfor Aja structures such as `Aja.Vector` or `Aja.OrdMap`.\n\n`Aja.Enum` on vectors/ord maps can often be faster than `Enum` on lists/maps,\ndepending on the function and size of the sequence.\n\n## Installation\n\nAja can be installed by adding `aja` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:aja, \"~\u003e 0.7.4\"}\n  ]\nend\n```\n\nOr you can just try it out from `iex` or an `.exs` script:\n\n```elixir\niex\u003e Mix.install([:aja])\n:ok\niex\u003e Aja.Vector.new([\"Hello\", \"world!\"])\nvec([\"Hello\", \"world!\"])\n```\n\nDocumentation can be found at [https://hexdocs.pm/aja](https://hexdocs.pm/aja).\n\n## About Aja\n\n### Inspirations\n\n- the amazingly polished [Elixir standard library](https://hexdocs.pm/elixir):\n  self-consistent, well-documented and just **delightful** ✨️\n- the also amazing\n  [Python standard library](https://docs.python.org/3/library/), notably its\n  [collections](https://docs.python.org/3/library/collections.html) module\n- various work on efficient\n  [persistent data structures](https://en.wikipedia.org/wiki/Persistent_data_structure)\n  spearheaded by Okasaki\n- Clojure's persistent vectors, by Rich Hickey and influenced by Phil Bagwell\n\n### Goals\n\n- being consistent with Elixir and with itself (API, quality, documentation)\n- no external dependency to help you preserve a decent dependency tree\n- performance-conscious (right algorithm, proper benchmarking, fast compile\n  times\\*)\n- mostly dead-simple pure functions: no configuration, no mandatory macro, no\n  statefulness / OTP\n\n(\\* while fast compile time is a target, vectors are optimized for fast runtime\nat the expense of compile time)\n\n### Resources\n\n- Chris Okasaki's\n  [Purely Functional Data Structures](https://www.cs.tufts.edu/~nr/cs257/archive/chris-okasaki/dissertation.pdf)\n- Jean Niklas L'orange's\n  [articles](https://hypirion.com/musings/understanding-persistent-vector-pt-1)\n  and [thesis](https://hypirion.com/thesis.pdf) about persistent vectors and RRB\n  trees\n\n## FAQ\n\n### How stable is it?\n\nAja is still pretty early stage and the high-level organisation is still in\nflux. Expect some breaking changes until it reaches maturity.\n\nHowever, most of its APIs are based on the standard library and should therefore\nremain fairly stable.\n\nBesides, Aja is tested quite thoroughly both with unit tests and property-based\ntesting (especially for data structures). This effort is far from perfect, but\nincreases our confidence in the overall reliability.\n\n### How is the performance?\n\n#### Vectors\n\nMost operations from `Aja.Vector` are much faster than Erlang's `:array`\nequivalents, and in some cases are even noticeably faster than equivalent list\noperations (map, folds, join, sum...). Make sure to read the efficiency guide\nfrom `Aja.Vector` doc.\n\n#### Ordered maps\n\nPerformance for ordered maps has an inevitable though decent overhead over plain\nmaps in terms of creation and update time (write operations), as well as memory\nusage, since some extra work is needed to keep track of the order. It has\nhowever very good read performance, with a very minimal overhead in terms of key\naccess, and can be enumerated much faster than maps using `Aja.Enum`.\n\n#### Aja 💖️ JIT\n\nAja's data structures (vectors and ordered maps) are already pretty fast on\npre-JIT versions of OTP (`\u003c= 23`). Benchmarks on OTP 24 suggest however that\nthey are taking great advantage of the\n[JIT](https://blog.erlang.org/a-first-look-at-the-jit/), relative to lists/maps,\nmaking them even more interesting performance-wise.\n\n#### Benchmarks\n\nAja data structures should work fine in most cases, but if you're considering\nthem for performance-critical sections of your code, make sure to benchmark\nthem.\n\nBenchmarking is still a work in progress, but you can check the\n[`bench` folder](https://github.com/sabiwara/aja/blob/main/bench) for more\ndetailed figures.\n\n## Copyright and License\n\nAja is licensed under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsabiwara%2Faja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsabiwara%2Faja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsabiwara%2Faja/lists"}