{"id":17328506,"url":"https://github.com/jhspetersson/packrat","last_synced_at":"2025-04-14T17:30:54.963Z","repository":{"id":236518146,"uuid":"792765137","full_name":"jhspetersson/packrat","owner":"jhspetersson","description":"Gatherers library for Java Stream API","archived":false,"fork":false,"pushed_at":"2024-10-23T07:39:29.000Z","size":226,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-01T05:24:34.481Z","etag":null,"topics":["gatherer","gatherers","java","jdk22","jdk23","preview-features","streams","streams-api"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jhspetersson.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":"2024-04-27T14:13:03.000Z","updated_at":"2024-10-25T10:53:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"b0a6f3a7-5669-44b4-8c40-1eb8799511f3","html_url":"https://github.com/jhspetersson/packrat","commit_stats":null,"previous_names":["jhspetersson/packrat"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhspetersson%2Fpackrat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhspetersson%2Fpackrat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhspetersson%2Fpackrat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhspetersson%2Fpackrat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jhspetersson","download_url":"https://codeload.github.com/jhspetersson/packrat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223639403,"owners_count":17177816,"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":["gatherer","gatherers","java","jdk22","jdk23","preview-features","streams","streams-api"],"created_at":"2024-10-15T14:24:21.365Z","updated_at":"2025-04-14T17:30:54.947Z","avatar_url":"https://github.com/jhspetersson.png","language":"Java","funding_links":[],"categories":["Projects"],"sub_categories":["Functional Programming"],"readme":"# Packrat\n\nPackrat is a Java library that provides various [Gatherer](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/util/stream/Gatherer.html) implementations for the Stream API. Gatherers can enhance streams with custom intermediate operations.\n\n[Introduction to the Gatherers by Viktor Klang](https://www.youtube.com/watch?v=8fMFa6OqlY8)\n\n### Availability\n\n\u003e [!IMPORTANT]\n\u003e You will need a very fresh JDK version with preview features enabled to actually use Gatherers.\n\n|JEP|JDK|Status|\n|---|---|---|\n|[461](https://openjdk.org/jeps/461)|22|Preview|\n|[473](https://openjdk.org/jeps/473)|23|Second Preview|\n|[485](https://openjdk.org/jeps/485)|24|Final|\n\n### Gatherers\n\n| Name                                                | Description                                            |\n|-----------------------------------------------------|--------------------------------------------------------|\n| [distinctBy](#distinctby)                           | Distinct values with custom mapper                     |\n| [filterBy](#filterby)                               | Filter with custom mapper and (optionally) predicate   |\n| [minBy](#minby)                                     | The smallest element compared after mapping applied    |\n| [maxBy](#maxby)                                     | The greatest element compared after mapping applied    |\n| [removeBy](#removeby)                               | Remove with custom mapper and (optionally) predicate   |\n| [increasing](#increasing)                           | Increasing sequence, other elements dropped            |\n| [increasingOrEqual](#increasingorequal)             | Increasing (or equal) sequence, other elements dropped |\n| [decreasing](#decreasing)                           | Decreasing sequence, other elements dropped            |\n| [decreasingOrEqual](#decreasingorequal)             | Decreasing (or equal) sequence, other elements dropped |\n| [increasingChunks](#increasingchunks)               | Lists of increasing values                             |\n| [increasingOrEqualChunks](#increasingorequalchunks) | Lists of increasing or equal values                    |                    \n| [decreasingChunks](#decreasingchunks)               | Lists of decreasing values                             |\n| [decreasingOrEqualChunks](#decreasingorequalchunks) | Lists of decreasing or equal values                    |\n| [reverse](#reverse)                                 | All elements in reverse order                          |\n| [rotate](#rotate)                                   | All elements rotated left or right                     |\n| [shuffle](#shuffle)                                 | All elements in random order                           |\n| [sample](#sample)                                   | Sample of the specified size                           |\n| [last](#last)                                       | Last __n__ elements                                    |\n| [lastUnique](#lastunique)                           | Last __n__ unique elements                             |\n| [chars](#chars)                                     | String splitted by Unicode graphemes                   |\n| [words](#words)                                     | String splitted by words                               |\n| [sentences](#sentences)                             | String splitted by sentences                           |\n| [nCopies](#ncopies)                                 | Copies every element __n__ times                       |\n| [atLeast](#atleast)                                 | Distinct values that appear at least __n__ times       |\n| [mapFirst](#mapfirst)                               | Maps first element with mapper, other unchanged        |\n| [mapN](#mapn)                                       | Maps __n__ elements, other unchanged                   |\n| [skipAndMap](#skipandmap)                           | Skips __n__ elements, maps others                      |\n| [skipAndMapN](#skipandmapn)                         | Skips __skipN__ elements, maps __mapN__ others         | \n| [flatMapIf](#flatmapif)                             | Optional `flatMap` depending on predicate              |\n| [zip](#zip)                                         | Zips values with zipper, leftovers dropped             |\n| [zipWithIndex](#zipwithindex)                       | Zips values with an increasing index                   |\n| [asGatherer](#asgatherer)                           | Converts `Collector` into `Gatherer`                   |\n\n#### distinctBy\n\n`distinctBy(mapper)` - returns elements with distinct values that result from a mapping by the supplied function\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.distinctBy;\n  var oneOddOneEven = IntStream.range(1, 10).boxed().gather(distinctBy(i -\u003e i % 2)).toList();\n  System.out.println(oneOddOneEven);\n```\n\u003e [1, 2]\n\n#### filterBy\n\n`filterBy(mapper, value)` - filters mapped elements based on the equality to the value, stream continues with original elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.filterBy;\n  var oneDigitNumbers = IntStream.range(0, 100).boxed().gather(filterBy(i -\u003e i.toString().length(), 1)).toList();\n  System.out.println(oneDigitNumbers);\n```\n\u003e [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n`filterBy(mapper, value, predicate)` - filters mapped elements based on the predicate test against the value, stream continues with original elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.filterBy;\n  var ffValue = IntStream.range(0, 1000).boxed().gather(filterBy(Integer::toHexString, \"ff\", String::equalsIgnoreCase)).toList();\n  System.out.println(ffValue);\n```\n\u003e [255]\n\n#### minBy\n\n`minBy(mapper)` - returns the smallest element in the stream, comparing is done after mapping function applied.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.minBy;\n  var check = Stream.of(\"2\", \"1\", \"-12\", \"22\", \"10\").gather(minBy(Long::parseLong)).toList();\n  System.out.println(check);\n```\n\n\u003e [-12]\n\nHowever, resulting list contains original element of type `String`;\n\n`minBy(mapper, comparator)` - returns the smallest element in the stream, comparing with given comparator is done after mapping function applied.\n\n#### maxBy\n\n`maxBy(mapper)` - returns the greatest element in the stream, comparing is done after mapping function applied.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.maxBy;\n  var check = Stream.of(\"2\", \"1\", \"-12\", \"22\", \"10\").gather(maxBy(Long::parseLong)).toList();\n  System.out.println(check);\n```\n\n\u003e [22]\n\nHowever, resulting list contains original element of type `String`;\n\n`maxBy(mapper, comparator)` - returns the greatest element in the stream, comparing with given comparator is done after mapping function applied.\n\n#### removeBy\n\n`removeBy(mapper, value)` - removes mapped elements based on the equality to the value, stream continues with original elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.removeBy;\n  var oneDigitNumbers = IntStream.range(0, 100).boxed().gather(removeBy(i -\u003e i.toString().length(), 2)).toList();\n  System.out.println(oneDigitNumbers);\n```\n\u003e [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n`removeBy(mapper, value, predicate)` - removes mapped elements based on the predicate test against the value, stream continues with original elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.removeBy;\n  var ageDivisibleByThree = getEmployees().gather(removeBy(emp -\u003e emp.age() % 3, 0, (i, value) -\u003e !Objects.equals(i, value))).toList();\n  System.out.println(ageDivisibleByThree);\n```\n\u003e [Employee[name=Mark Bloom, age=21], Employee[name=Rebecca Schneider, age=24]]\n\n#### increasing\n\n`increasing()` - returns elements in an increasing sequence, elements out of the sequence, as well as repeating values, are dropped\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.increasing;\n  var numbers = Stream.of(1, 2, 2, 5, 4, 2, 6, 9, 3, 11, 0, 1, 20);\n  var increasingNumbers = numbers.gather(increasing()).toList();\n  System.out.println(increasingNumbers);\n```\n\n\u003e [1, 2, 5, 6, 9, 11, 20]\n\n#### increasingOrEqual\n\n`increasingOrEqual()` - returns elements in an increasing sequence, repeating values are preserved, elements out of the sequence are dropped\n\n#### decreasing\n\n`decreasing()` - returns elements in a decreasing sequence, elements out of the sequence, as well as repeating values, are dropped\n\n#### decreasingOrEqual\n\n`decreasingOrEqual()` - returns elements in a decreasing sequence, repeating values are preserved, elements out of the sequence are dropped\n\n#### increasingChunks\n\n`increasingChunks()` - returns lists (\"chunks\") of elements, where each next element is greater than the previous one\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.increasingChunks;\n  var numbers = Stream.of(1, 2, 2, 5, 4, 2, 6, 9, 3, 11, 0, 1, 20);\n  var result = numbers.gather(increasingChunks()).toList();\n  System.out.println(result);\n```\n\n\u003e [[1, 2], [2, 5], [4], [2, 6, 9], [3, 11], [0, 1, 20]]\n\n#### increasingOrEqualChunks\n\n`increasingOrEqualChunks()` - returns lists (\"chunks\") of elements, where each next element is greater or equal than the previous one\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.increasingOrEqualChunks;\n  var numbers = Stream.of(1, 2, 2, 5, 4, 2, 6, 9, 3, 11, 0, 1, 20);\n  var result = numbers.gather(increasingOrEqualChunks()).toList();\n  System.out.println(result);\n```\n\n\u003e [[1, 2, 2, 5], [4], [2, 6, 9], [3, 11], [0, 1, 20]]\n\n#### decreasingChunks\n\n`decreasingChunks()` - returns lists (\"chunks\") of elements, where each next element is less than the previous one\n\n#### decreasingOrEqualChunks\n\n`decreasingOrEqualChunks()` - returns lists (\"chunks\") of elements, where each next element is less or equal than the previous one\n\n#### reverse\n\n`reverse()` - reverses the elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.reverse;\n  var reverseOrdered = IntStream.range(0, 10).boxed().gather(reverse()).toList();\n  System.out.println(reverseOrdered);\n```\n\u003e [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n\n#### rotate\n\n`rotate(distance)` - rotates the elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.rotate;\n  var positiveRotation = IntStream.range(0, 10).boxed().gather(rotate(3)).toList();\n  System.out.println(positiveRotation);\n  var negativeRotation = IntStream.range(0, 10).boxed().gather(rotate(-4)).toList();\n  System.out.println(negativeRotation);\n```\n\u003e [7, 8, 9, 0, 1, 2, 3, 4, 5, 6]\n\n\u003e [4, 5, 6, 7, 8, 9, 0, 1, 2, 3]\n\n#### shuffle\n\n`shuffle()` - shuffle the elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.shuffle;\n  var randomlyOrdered = IntStream.range(0, 10).boxed().gather(shuffle()).toList();\n  System.out.println(randomlyOrdered);\n```\n\u003e [2, 7, 6, 9, 8, 5, 1, 3, 0, 4]\n\n#### sample\n\n`sample(n)` - returns a sample of the specified size from the stream of elements.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.sample;\n  var source = IntStream.range(0, 100).boxed().gather(sample(10)).toList();\n  System.out.println(source);\n```\n\u003e [0, 8, 27, 33, 65, 66, 88, 90, 93, 96]\n\n`sample(n, maxSpan)` - returns a sample of the specified size from the stream of elements, inspects first __maxSpan__ elements.\n\n#### last\n\n`last(n)` - returns __n__ last elements from the stream.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.last;\n  var integers = IntStream.range(0, 100).boxed().gather(last(10)).toList();\n  System.out.println(integers);\n```\n\n\u003e [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n\n#### lastUnique\n\n`lastUnique(n)` - returns __n__ last unique elements from the stream.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.lastUnique;\n  var integers = List.of(1, 2, 3, 4, 5, 4, 1, 1, 1, 2, 2, 6).stream().gather(lastUnique(3)).toList();\n  System.out.println(integers);\n```\n\n\u003e [1, 2, 6]\n\n#### chars\n\n`chars()` - returns characters as strings parsed from the stream elements\n  \n```java\n  import static io.github.jhspetersson.packrat.Packrat.chars;\n  var charStrings = Stream.of(\"Hello, \\uD83D\\uDC22!\").gather(chars()).toList();\n  System.out.println(charStrings);\n```\n\n\u003e [H, e, l, l, o, ,,  , 🐢, !]\n\n#### words\n\n`words()` - returns words as strings parsed from the stream elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.words;\n  var wordStrings = Stream.of(\"Another test!\").gather(words()).toList();\n  System.out.println(wordStrings);\n```\n\n\u003e [Another, test, !]\n\n#### sentences\n\n`sentences()` - returns sentences as strings parsed from the stream elements\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.sentences;\n  var sentenceStrings = Stream.of(\"And another one. How many left?\").gather(sentences()).toList();\n  System.out.println(sentenceStrings);\n```\n\n\u003e [And another one. , How many left?]\n\n#### nCopies\n\n`nCopies(n)` - returns __n__ copies of every element, __n__ less than or equal to zero effectively empties the stream\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.nCopies;\n  var numbers = IntStream.of(5).boxed().gather(nCopies(10)).toList();\n  System.out.println(numbers);\n```\n\n\u003e [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]\n\n#### atLeast\n\n`atLeast(n)` - returns distinct elements that appear at least __n__ times in the stream\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.atLeast;\n  var numbers = Stream.of(1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 8, 8, 8, 9, 10);\n  var atLeastThree = numbers.gather(atLeast(3)).toList();\n  System.out.println(atLeastThree);\n```\n\u003e [3, 3, 3, 8, 8, 8, 8]\n\n#### mapFirst\n\n`mapFirst(mapper)` - returns all elements, the first element is mapped with the supplied mapping function\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.mapFirst;\n  var mapped = IntStream.rangeClosed(1, 10).boxed().gather(mapFirst(n -\u003e n * 10)).toList();\n  System.out.println(mapped);\n```\n\n\u003e [10, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n#### mapN\n\n`mapN(n, mapper)` - returns all elements, the first __n__ elements are mapped with the supplied mapping function\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.mapN;\n  var mapped = IntStream.rangeClosed(1, 10).boxed().gather(mapN(5, n -\u003e n * 10)).toList();\n  System.out.println(mapped);\n```\n\n\u003e [10, 20, 30, 40, 50, 6, 7, 8, 9, 10]\n\n#### skipAndMap\n\n`skipAndMap(n, mapper)` - returns all elements that after the first __n__ are mapped with the supplied mapping function\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.skipAndMap;\n  var mapped = IntStream.rangeClosed(1, 10).boxed().gather(skipAndMap(3, n -\u003e n * 10)).toList();\n  System.out.println(mapped);\n```\n\n\u003e [1, 2, 3, 40, 50, 60, 70, 80, 90, 100]\n\n#### skipAndMapN\n\n`skipAndMapN(skipN, mapN, mapper)` - returns all elements, after __skipN__ elements the first __mapN__ elements are mapped with the supplied mapping function\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.skipAndMapN;\n  var mapped = IntStream.rangeClosed(1, 10).boxed().gather(skipAndMapN(3, 5, n -\u003e n * 10)).toList();\n  System.out.println(mapped);\n```\n\n\u003e [1, 2, 3, 40, 50, 60, 70, 80, 9, 10]\n\n#### flatMapIf\n\n`flatMapIf(mapper, predicate)` - optionally flattens elements mapped to streams depending on the supplied predicate\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.flatMapIf;\n  var strings = Stream.of(\"A\", \"B\", \"CDE\");\n  var result = strings.gather(flatMapIf(s -\u003e Arrays.stream(s.split(\"\")), s -\u003e s.length() \u003e 1)).toList();\n  System.out.println(result);\n```\n\n\u003e [A, B, C, D, E]\n\n#### zip\n\n`zip(input, mapper)` - returns elements mapped (\"zipped\") with the values from some other stream, iterable or iterator.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.zip;\n  var names = List.of(\"Anna\", \"Mike\", \"Sandra\");\n  var ages = Stream.of(20, 30, 40, 50, 60, 70, 80, 90);\n  var users = names.stream().gather(zip(ages, User::new)).toList();\n  System.out.println(users);\n```\n\n\u003e [User[name=Anna, age=20], User[name=Mike, age=30], User[name=Sandra, age=40]]\n\n`zip(input)` - zips current stream and input into Map entries.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.zip;\n  var names = List.of(\"Anna\", \"Mike\", \"Sandra\");\n  var ages = Stream.of(20, 30, 40);\n  var users = names.stream().gather(zip(ages)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n  System.out.println(users);\n```\n\n\u003e {Mike=30, Anna=20, Sandra=40}\n\n#### zipWithIndex\n\n`zipWithIndex()` - zips current stream with an increasing index into Map entries.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;\n  var names = List.of(\"Anna\", \"Mike\", \"Sandra\");\n  var users = names.stream().gather(zipWithIndex()).toList();\n```\n\n\u003e [0=Anna, 1=Mike, 2=Sandra]\n\n`zipWithIndex(startIndex)` - zips current stream with an increasing index (beginning with _startIndex_) into Map entries.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;\n  var names = List.of(\"Anna\", \"Mike\", \"Sandra\");\n  var users = names.stream().gather(zipWithIndex(10)).toList();\n```\n\n\u003e [10=Anna, 11=Mike, 12=Sandra]\n\n`zipWithIndex(mapper)` - zips current stream with an increasing index, mapping function receives the index as the first argument.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;\n  var names = List.of(\"Anna\", \"Mike\", \"Sandra\");\n  var users = names.stream().gather(zipWithIndex(User::new)).toList();\n```\n\n\u003e [User[index=0, name=Anna], User[index=1, name=Mike], User[index=2, name=Sandra]]\n\n`zipWithIndex(mapper, startIndex)` - zips current stream with an increasing index (beginning with _startIndex_), mapping function receives the index as the first argument.\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;\n  var names = List.of(\"Anna\", \"Mike\", \"Sandra\");\n  var users = names.stream().gather(zipWithIndex(User::new, 10)).toList();\n```\n\n\u003e [User[index=10, name=Anna], User[index=11, name=Mike], User[index=12, name=Sandra]]\n\n#### asGatherer\n\n`asGatherer(collector)` - provides the result of the supplied collector as a single element into the stream, effectively converts any Collector into a Gatherer\n\n```java\n  import static io.github.jhspetersson.packrat.Packrat.asGatherer;\n  var numbers = Stream.of(1, 2, 3, 4, 5);\n  var listOfCollectedList = numbers.gather(asGatherer(Collectors.toList())).toList();\n  System.out.println(listOfCollectedList);\n```\n\n\u003e [[1, 2, 3, 4, 5]]\n\n### License\n\nApache-2.0\n\n---\nSupported by [JetBrains IDEA](https://jb.gg/OpenSourceSupport) open source license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhspetersson%2Fpackrat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjhspetersson%2Fpackrat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhspetersson%2Fpackrat/lists"}