{"id":13735652,"url":"https://github.com/hamidb80/iterrr","last_synced_at":"2025-08-25T23:04:47.872Z","repository":{"id":38187454,"uuid":"463829053","full_name":"hamidb80/iterrr","owner":"hamidb80","description":"iterate faster ... 🏎️. functional-style, extensible iterator library","archived":false,"fork":false,"pushed_at":"2023-12-30T17:20:31.000Z","size":171,"stargazers_count":73,"open_issues_count":3,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-10T14:42:07.494Z","etag":null,"topics":["functional-style","iterator","lazy","library","nim"],"latest_commit_sha":null,"homepage":"","language":"Nim","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/hamidb80.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","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}},"created_at":"2022-02-26T11:05:56.000Z","updated_at":"2025-01-27T09:51:43.000Z","dependencies_parsed_at":"2024-01-06T11:44:05.024Z","dependency_job_id":null,"html_url":"https://github.com/hamidb80/iterrr","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/hamidb80/iterrr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamidb80%2Fiterrr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamidb80%2Fiterrr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamidb80%2Fiterrr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamidb80%2Fiterrr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hamidb80","download_url":"https://codeload.github.com/hamidb80/iterrr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamidb80%2Fiterrr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272144649,"owners_count":24881141,"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-25T02:00:12.092Z","response_time":1107,"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":["functional-style","iterator","lazy","library","nim"],"created_at":"2024-08-03T03:01:09.349Z","updated_at":"2025-08-25T23:04:47.829Z","avatar_url":"https://github.com/hamidb80.png","language":"Nim","funding_links":[],"categories":["Language Features"],"sub_categories":["Iteration"],"readme":"\u003e Once a young man approached the Prophet Muhammad and asked him for some advice. The Prophet replied, “Do not become angry,” and he repeated this three times\n\n[![ReadMeSupportPalestine](https://raw.githubusercontent.com/Safouene1/support-palestine-banner/master/banner-support.svg)](https://github.com/Safouene1/support-palestine-banner)\n\n# iterrr!\niterate faster ... 🏎️.\nWrite higher-order functions, get its imperative style at the compile time!\n\n## The Problem\nWriting a full nested loop is a boring task, `std/sequtils` creates lots of temporary `seq`s, [iterutils](https://github.com/def-/nim-iterutils) uses closure iterators (which is slow).\n\n## The Solution\n`iterrr` uses the *ultimate* power of meta-programming to bring you the speed that Nim programmers deserve.\n\n## example of generated code\n```nim\n\"hello\".pairs |\u003e \n  filter((i, _) =\u003e i  \u003e 1)\n  .map((_, ch) =\u003e ch)\n  .strjoin() ## llo\n```\n\n```nim\nblock:\n  template iterrrFn3(_; ch): untyped {.dirty.} =\n    ch\n\n  template iterrrFn4(i; _): untyped {.dirty.} =\n    i \u003e 1\n\n  var iterrrAcc2 = strjoinInit[typeof(iterrrFn3(\n      default(typeof(\"hello\".pairs))[0], default(typeof(\"hello\".pairs))[1]))]()\n  block mainLoop:\n    for li1 in \"hello\".pairs:\n      if iterrrFn4(li1[0], li1[1]):\n        block:\n          let li1 = iterrrFn3(li1[0], li1[1])\n          if not strjoinUpdate(iterrrAcc2, li1):\n            break mainLoop\n  strjoinFinalizer(iterrrAcc2)\n```\n\n## Usage\n\n### complete syntax\n**There is 3 type of usage:**\n```nim\n# predefined reducer\niterable |\u003e entity1(_).entity2(_)...Reducer()\n\n# custom reducer\niterable |\u003e entity1(_).entity2(_)...reduce(loopIdents, accIdent = initial_value, [Finalizer]):\n  # update accIdent\n\n# custom code\niterable |\u003e entity1(_).entity2(_)...each(...loopIdents):\n  # do with loopIdents\n```\n\n### Main Entities:\n1. **map** :: similar to `mapIt` from `std/sequtils`\n2. **filter** :: similar to `filterIt` from `std/sequtils`\n3. **breakif** :: similar to `takeWhile` in functional programming languages but negative.\n4. **inject** :: injects custom code\n\n#### 1. predefined reducer\n**NOTE:** you can chain as many `map`/`filter`/... as you want in any order, but there is **only one** reducer.\n\n\n**There are some predefined reducers in iterrr library:**\n* `toSeq` :: stores elements into a `seq`\n* `count` :: counts elements\n* `sum` :: calculates summation\n* `min` :: calculates minimum\n* `max` :: calculates maximum\n* `first` :: returns the first item\n* `last` :: returns the last item\n* `any` :: similar to `any` from `std/sequtils`\n* `all` :: similar to `all` from `std/sequtils`\n* `toHashSet` :: stores elements into a `HashSet`\n* `strJoin` :: similar to `join` from `std/strutils`\n* `toCountTable` :: similar to `toCountTable` from `std/tables`\n\nhere's how you can get maximum x, when `flatPoints` is: `[x0, y0, x1, y1, x2, y2, ...]`\n```nim\nlet xmax = flatPoints.pairs |\u003e filter(it[0] mod 2 == 0).map(it[1]).max()\n# or\nlet xmax = countup(0, flatPoints.high, 2) |\u003e map(flatPoints[it]).max()\n```\n\n**NOTE**: see more examples in `tests/test.nim`\n\n### Custom Idents ?!?\nusing just `it` in `mapIt` and `filterIt` is just ... and makes code a little unreadable.\n\n#### remember these principles when using custom ident:\n1. if there was no custom idents, `it` is assumed\n2. if there was only 1 custom ident, the custom ident is replaced with `it`\n3. if there was more than 1 custom idents, `it` is unpacked \n\n**Here's some examples**:  \n```nim\n(1..10) |\u003e map( _ ) # \"it\" is available inside the \"map\"\n(1..10) |\u003e map(n =\u003e _ )\n(1..10) |\u003e map((n) =\u003e _ )\n(1..10) |\u003e map((a1, a2, ...) =\u003e _ )\n(1..10) |\u003e reduce((a1, a2, ...), acc = 2)\n(1..10) |\u003e each(a1, a2)\n```\nCustom idents work with both `op:` and `op()` style syntax:\n```nim\n(1..10).items.iterrr:\n  map: n =\u003e _\n  # or map n =\u003e _\n  ...\n(1..10).items.iterrr:\n  filter: (n, k) =\u003e _\n  # or filter (n, k) =\u003e _\n  ...\n```\n\n**example**:\n```nim\n\"hello\".pairs |\u003e filter((i, c) =\u003e i \u003e 2).map((_, c) =\u003e ord c)\n```\n\n### Limitation\nyou have to specify the iterator for `seq` and other iterable objects [`HSlice` is an exception]\n\n**example:**\n```nim\nlet s = [1, 2, 3]\necho s |\u003e map($it).toseq() # doesn't work\necho s.items |\u003e map($it).toseq() # works fine\necho s.pairs |\u003e map($it).toseq() # works fine\n```\n\n### Define Your Reducer!\n**every reducer have**: [let't name our custom reducer `zzz`]\n1. `zzzInit[T](args...): ...` :: initializes the value of accumulator(state) :: must be *generic*.\n2. `zzzUpdate(var acc, newValue): bool` :: updates the accumulator based on `newValue`, if returns false, the iteration stops.\n3. `zzzFinalizer(n): ...` :: returns the result of the accumulator.\n\n**NOTE**: see implementations in `src/iterrr/reducers.nim`\n\n### Custom Reducer\n**pattern**:\n```nim\nITER |\u003e ...reduce(idents, acc = initial_value, [finalizer]): \n   update acc here \n```\n\n**Notes**:\n- acc can be any ident like `result` or `answer`, ... \n- **Finalizer**:\n  - it's optional\n  - it's an experssion inside of it you have access to the `acc` ident\n  - the default finalizer is `acc` ident \n\n**Example of searching for a number**:\n```nim\nlet element = (1..10) |\u003e reduce(it, answer = none int, answer.get):\n  if your_condition(it):\n    answer = some MyNumber\n    break mainLoop\n```\n**Note**: if the item has not found, raises `UnpackDefect` error as result of `get` function  in finalizer `answer.get`.\n\n### Don't Wanna Use Reducer?\n\u003e My view is that a lot of the time in Nim when you're doing filter or map you're just going to operate it on afterwards\n:: [@beef331](https://github.com/beef331) AKA beef.\n\nI'm agree with beef. it happens a lot. \nyou can do it with `each(arg1, arg2,...)`. [arguments semantic is the same as custom idents]\n```nim\n(1..10) |\u003e filter(it in 3..5).each(num):\n  echo num\n  if num \u003c 7:\n    break mainLoop\n```\n\n**Note**: `mainLoop` is the main loop block\n\n### Custom Adapter\nadapters are inspired from implmentation of iterators in Nim.\nTODO: explain more\n\n**Limitations**: you have to import the dependencies of adapters in order to use them.\n\n**Built-in adapter**:\n- `group`\n- `window`\n- `cycle`\n- `flatten`\n- `drop`\n- `take`\n\n**Usage**: \nexample:\n\n```nim\nlet matrix = [\n  [1, 2, 3],\n  [4, 5, 6],\n  [7, 8, 9]\n]\nmatrix.items |\u003e flatten().map(-it).cycle(11).group(4).toseq()\n```\nresult:\n```nim\n@[\n  @[-1, -2, -3, -4], \n  @[-5, -6, -7, -8], \n  @[-9, -1, -2] \n]\n```\n\n*see `tests`/`test.nim` for more.*\n\n**Define your custom adapter**:\nfor now the name of loop iterator are limited to `it`.\nTODO; \nsee `src`/`iterrr`/`adapters`.\n\n## `iterrr` macro\ndon't like `|\u003e` operator? no problem! use `iterrr` keyword:\n\npattern:\n```nim\niterable.iterator.iterrr:\n  filter(...)\n  map(...)\n  reducer(...)\n  reduce(...)/each(...):\n    # code ...\n```\n\nexample:\n```nim\nlet points = @[(1, 2), (-3, 4), (12, 3), (-1, -6), (5, -9)]\n\npoints.items.iterrr:\n  map (x, y) =\u003e x # or map((x, y) =\u003e x)\n  filter it \u003e 0   # or filter(it \u003e 0)\n  each n:         # or each(n):\n    echo n\n```\n\n## Nesting\n\nBoth the `|\u003e` operator and `iterrr` macro can be nested.\n\nExamples:\n\n```nim\nmatrix.pairs |\u003e map((ia, a) =\u003e (\n    a.pairs |\u003e map((ib, _) =\u003e (ia, ib)).toseq()\n  )).toseq()\n```\n\n```nim\nmatrix.pairs.iterrr:\n  map: (ia, a) =\u003e a.pairs.iterrr:\n    map: (ib, _) =\u003e (ia, ib)\n    toseq()\n  toseq()\n```\n\n## Debugging\nuse `-d:iterrrDebug` flag to see generated code.\n\n## Breaking changes\n### `0.x` -\u003e `1.x`:\n- using brackets for defining custom idents is no longer supported.\n\n\n## Inspirations\n1. [zero_functional](https://github.com/zero-functional/zero-functional)\n2. [itertools](https://github.com/narimiran/itertools)\n3. [slicerator](https://github.com/beef331/slicerator)\n4. [xflywind's comment on this issue](https://github.com/nim-lang/Nim/issues/18405#issuecomment-888391521)\n5. [mangle](https://github.com/baabelfish/mangle/)\n\n## Common Questions:\n### `iterrr` VS `zero_functional`:\n`iterrr` targets the same problem as `zero_functional`, while being better at  *extensibility*.\n\n**Is it fully \"zero cost\" like `zero_functional` though?**\n\u003e well NO, most of it is because of reducer update calls, however the speed difference is soooo tiny and you can't even measure it. I could define all reducer updates as `template` instead of function but IMO it's better to have call stack when you hit errors ...\n\n## Quotes\n\u003e writing macro is kind of addicting...\n:: [PMunch](https://github.com/PMunch/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamidb80%2Fiterrr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhamidb80%2Fiterrr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamidb80%2Fiterrr/lists"}