Packrat is a Java library that provides various Gatherer implementations for the Stream API. Gatherers can enhance streams with custom intermediate operations.
Introduction to the Gatherers by Viktor Klang
Important
You will need a very fresh JDK version with preview features enabled to actually use Gatherers.
JEP | JDK | Status |
---|---|---|
461 | 22 | Preview |
473 | 23 | Second Preview |
485 | 24 | Final |
Name | Description |
---|---|
distinctBy | Distinct values with custom mapper |
filterBy | Filter with custom mapper and (optionally) predicate |
minBy | The smallest element compared after mapping applied |
maxBy | The greatest element compared after mapping applied |
removeBy | Remove with custom mapper and (optionally) predicate |
increasing | Increasing sequence, other elements dropped |
increasingOrEqual | Increasing (or equal) sequence, other elements dropped |
decreasing | Decreasing sequence, other elements dropped |
decreasingOrEqual | Decreasing (or equal) sequence, other elements dropped |
increasingChunks | Lists of increasing values |
increasingOrEqualChunks | Lists of increasing or equal values |
decreasingChunks | Lists of decreasing values |
decreasingOrEqualChunks | Lists of decreasing or equal values |
reverse | All elements in reverse order |
rotate | All elements rotated left or right |
shuffle | All elements in random order |
sample | Sample of the specified size |
last | Last n elements |
lastUnique | Last n unique elements |
chars | String splitted by Unicode graphemes |
words | String splitted by words |
sentences | String splitted by sentences |
nCopies | Copies every element n times |
atLeast | Distinct values that appear at least n times |
mapFirst | Maps first element with mapper, other unchanged |
mapN | Maps n elements, other unchanged |
skipAndMap | Skips n elements, maps others |
skipAndMapN | Skips skipN elements, maps mapN others |
flatMapIf | Optional flatMap depending on predicate |
zip | Zips values with zipper, leftovers dropped |
zipWithIndex | Zips values with an increasing index |
asGatherer | Converts Collector into Gatherer |
distinctBy(mapper)
- returns elements with distinct values that result from a mapping by the supplied function
import static io.github.jhspetersson.packrat.Packrat.distinctBy;
var oneOddOneEven = IntStream.range(1, 10).boxed().gather(distinctBy(i -> i % 2)).toList();
System.out.println(oneOddOneEven);
[1, 2]
filterBy(mapper, value)
- filters mapped elements based on the equality to the value, stream continues with original elements
import static io.github.jhspetersson.packrat.Packrat.filterBy;
var oneDigitNumbers = IntStream.range(0, 100).boxed().gather(filterBy(i -> i.toString().length(), 1)).toList();
System.out.println(oneDigitNumbers);
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
filterBy(mapper, value, predicate)
- filters mapped elements based on the predicate test against the value, stream continues with original elements
import static io.github.jhspetersson.packrat.Packrat.filterBy;
var ffValue = IntStream.range(0, 1000).boxed().gather(filterBy(Integer::toHexString, "ff", String::equalsIgnoreCase)).toList();
System.out.println(ffValue);
[255]
minBy(mapper)
- returns the smallest element in the stream, comparing is done after mapping function applied.
import static io.github.jhspetersson.packrat.Packrat.minBy;
var check = Stream.of("2", "1", "-12", "22", "10").gather(minBy(Long::parseLong)).toList();
System.out.println(check);
[-12]
However, resulting list contains original element of type String
;
minBy(mapper, comparator)
- returns the smallest element in the stream, comparing with given comparator is done after mapping function applied.
maxBy(mapper)
- returns the greatest element in the stream, comparing is done after mapping function applied.
import static io.github.jhspetersson.packrat.Packrat.maxBy;
var check = Stream.of("2", "1", "-12", "22", "10").gather(maxBy(Long::parseLong)).toList();
System.out.println(check);
[22]
However, resulting list contains original element of type String
;
maxBy(mapper, comparator)
- returns the greatest element in the stream, comparing with given comparator is done after mapping function applied.
removeBy(mapper, value)
- removes mapped elements based on the equality to the value, stream continues with original elements
import static io.github.jhspetersson.packrat.Packrat.removeBy;
var oneDigitNumbers = IntStream.range(0, 100).boxed().gather(removeBy(i -> i.toString().length(), 2)).toList();
System.out.println(oneDigitNumbers);
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
removeBy(mapper, value, predicate)
- removes mapped elements based on the predicate test against the value, stream continues with original elements
import static io.github.jhspetersson.packrat.Packrat.removeBy;
var ageDivisibleByThree = getEmployees().gather(removeBy(emp -> emp.age() % 3, 0, (i, value) -> !Objects.equals(i, value))).toList();
System.out.println(ageDivisibleByThree);
[Employee[name=Mark Bloom, age=21], Employee[name=Rebecca Schneider, age=24]]
increasing()
- returns elements in an increasing sequence, elements out of the sequence, as well as repeating values, are dropped
import static io.github.jhspetersson.packrat.Packrat.increasing;
var numbers = Stream.of(1, 2, 2, 5, 4, 2, 6, 9, 3, 11, 0, 1, 20);
var increasingNumbers = numbers.gather(increasing()).toList();
System.out.println(increasingNumbers);
[1, 2, 5, 6, 9, 11, 20]
increasingOrEqual()
- returns elements in an increasing sequence, repeating values are preserved, elements out of the sequence are dropped
decreasing()
- returns elements in a decreasing sequence, elements out of the sequence, as well as repeating values, are dropped
decreasingOrEqual()
- returns elements in a decreasing sequence, repeating values are preserved, elements out of the sequence are dropped
increasingChunks()
- returns lists ("chunks") of elements, where each next element is greater than the previous one
import static io.github.jhspetersson.packrat.Packrat.increasingChunks;
var numbers = Stream.of(1, 2, 2, 5, 4, 2, 6, 9, 3, 11, 0, 1, 20);
var result = numbers.gather(increasingChunks()).toList();
System.out.println(result);
[[1, 2], [2, 5], [4], [2, 6, 9], [3, 11], [0, 1, 20]]
increasingOrEqualChunks()
- returns lists ("chunks") of elements, where each next element is greater or equal than the previous one
import static io.github.jhspetersson.packrat.Packrat.increasingOrEqualChunks;
var numbers = Stream.of(1, 2, 2, 5, 4, 2, 6, 9, 3, 11, 0, 1, 20);
var result = numbers.gather(increasingOrEqualChunks()).toList();
System.out.println(result);
[[1, 2, 2, 5], [4], [2, 6, 9], [3, 11], [0, 1, 20]]
decreasingChunks()
- returns lists ("chunks") of elements, where each next element is less than the previous one
decreasingOrEqualChunks()
- returns lists ("chunks") of elements, where each next element is less or equal than the previous one
reverse()
- reverses the elements
import static io.github.jhspetersson.packrat.Packrat.reverse;
var reverseOrdered = IntStream.range(0, 10).boxed().gather(reverse()).toList();
System.out.println(reverseOrdered);
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rotate(distance)
- rotates the elements
import static io.github.jhspetersson.packrat.Packrat.rotate;
var positiveRotation = IntStream.range(0, 10).boxed().gather(rotate(3)).toList();
System.out.println(positiveRotation);
var negativeRotation = IntStream.range(0, 10).boxed().gather(rotate(-4)).toList();
System.out.println(negativeRotation);
[7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
[4, 5, 6, 7, 8, 9, 0, 1, 2, 3]
shuffle()
- shuffle the elements
import static io.github.jhspetersson.packrat.Packrat.shuffle;
var randomlyOrdered = IntStream.range(0, 10).boxed().gather(shuffle()).toList();
System.out.println(randomlyOrdered);
[2, 7, 6, 9, 8, 5, 1, 3, 0, 4]
sample(n)
- returns a sample of the specified size from the stream of elements.
import static io.github.jhspetersson.packrat.Packrat.sample;
var source = IntStream.range(0, 100).boxed().gather(sample(10)).toList();
System.out.println(source);
[0, 8, 27, 33, 65, 66, 88, 90, 93, 96]
sample(n, maxSpan)
- returns a sample of the specified size from the stream of elements, inspects first maxSpan elements.
last(n)
- returns n last elements from the stream.
import static io.github.jhspetersson.packrat.Packrat.last;
var integers = IntStream.range(0, 100).boxed().gather(last(10)).toList();
System.out.println(integers);
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
lastUnique(n)
- returns n last unique elements from the stream.
import static io.github.jhspetersson.packrat.Packrat.lastUnique;
var integers = List.of(1, 2, 3, 4, 5, 4, 1, 1, 1, 2, 2, 6).stream().gather(lastUnique(3)).toList();
System.out.println(integers);
[1, 2, 6]
chars()
- returns characters as strings parsed from the stream elements
import static io.github.jhspetersson.packrat.Packrat.chars;
var charStrings = Stream.of("Hello, \uD83D\uDC22!").gather(chars()).toList();
System.out.println(charStrings);
[H, e, l, l, o, ,, , 🐢, !]
words()
- returns words as strings parsed from the stream elements
import static io.github.jhspetersson.packrat.Packrat.words;
var wordStrings = Stream.of("Another test!").gather(words()).toList();
System.out.println(wordStrings);
[Another, test, !]
sentences()
- returns sentences as strings parsed from the stream elements
import static io.github.jhspetersson.packrat.Packrat.sentences;
var sentenceStrings = Stream.of("And another one. How many left?").gather(sentences()).toList();
System.out.println(sentenceStrings);
[And another one. , How many left?]
nCopies(n)
- returns n copies of every element, n less than or equal to zero effectively empties the stream
import static io.github.jhspetersson.packrat.Packrat.nCopies;
var numbers = IntStream.of(5).boxed().gather(nCopies(10)).toList();
System.out.println(numbers);
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
atLeast(n)
- returns distinct elements that appear at least n times in the stream
import static io.github.jhspetersson.packrat.Packrat.atLeast;
var numbers = Stream.of(1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 8, 8, 8, 9, 10);
var atLeastThree = numbers.gather(atLeast(3)).toList();
System.out.println(atLeastThree);
[3, 3, 3, 8, 8, 8, 8]
mapFirst(mapper)
- returns all elements, the first element is mapped with the supplied mapping function
import static io.github.jhspetersson.packrat.Packrat.mapFirst;
var mapped = IntStream.rangeClosed(1, 10).boxed().gather(mapFirst(n -> n * 10)).toList();
System.out.println(mapped);
[10, 2, 3, 4, 5, 6, 7, 8, 9, 10]
mapN(n, mapper)
- returns all elements, the first n elements are mapped with the supplied mapping function
import static io.github.jhspetersson.packrat.Packrat.mapN;
var mapped = IntStream.rangeClosed(1, 10).boxed().gather(mapN(5, n -> n * 10)).toList();
System.out.println(mapped);
[10, 20, 30, 40, 50, 6, 7, 8, 9, 10]
skipAndMap(n, mapper)
- returns all elements that after the first n are mapped with the supplied mapping function
import static io.github.jhspetersson.packrat.Packrat.skipAndMap;
var mapped = IntStream.rangeClosed(1, 10).boxed().gather(skipAndMap(3, n -> n * 10)).toList();
System.out.println(mapped);
[1, 2, 3, 40, 50, 60, 70, 80, 90, 100]
skipAndMapN(skipN, mapN, mapper)
- returns all elements, after skipN elements the first mapN elements are mapped with the supplied mapping function
import static io.github.jhspetersson.packrat.Packrat.skipAndMapN;
var mapped = IntStream.rangeClosed(1, 10).boxed().gather(skipAndMapN(3, 5, n -> n * 10)).toList();
System.out.println(mapped);
[1, 2, 3, 40, 50, 60, 70, 80, 9, 10]
flatMapIf(mapper, predicate)
- optionally flattens elements mapped to streams depending on the supplied predicate
import static io.github.jhspetersson.packrat.Packrat.flatMapIf;
var strings = Stream.of("A", "B", "CDE");
var result = strings.gather(flatMapIf(s -> Arrays.stream(s.split("")), s -> s.length() > 1)).toList();
System.out.println(result);
[A, B, C, D, E]
zip(input, mapper)
- returns elements mapped ("zipped") with the values from some other stream, iterable or iterator.
import static io.github.jhspetersson.packrat.Packrat.zip;
var names = List.of("Anna", "Mike", "Sandra");
var ages = Stream.of(20, 30, 40, 50, 60, 70, 80, 90);
var users = names.stream().gather(zip(ages, User::new)).toList();
System.out.println(users);
[User[name=Anna, age=20], User[name=Mike, age=30], User[name=Sandra, age=40]]
zip(input)
- zips current stream and input into Map entries.
import static io.github.jhspetersson.packrat.Packrat.zip;
var names = List.of("Anna", "Mike", "Sandra");
var ages = Stream.of(20, 30, 40);
var users = names.stream().gather(zip(ages)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(users);
{Mike=30, Anna=20, Sandra=40}
zipWithIndex()
- zips current stream with an increasing index into Map entries.
import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;
var names = List.of("Anna", "Mike", "Sandra");
var users = names.stream().gather(zipWithIndex()).toList();
[0=Anna, 1=Mike, 2=Sandra]
zipWithIndex(startIndex)
- zips current stream with an increasing index (beginning with startIndex) into Map entries.
import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;
var names = List.of("Anna", "Mike", "Sandra");
var users = names.stream().gather(zipWithIndex(10)).toList();
[10=Anna, 11=Mike, 12=Sandra]
zipWithIndex(mapper)
- zips current stream with an increasing index, mapping function receives the index as the first argument.
import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;
var names = List.of("Anna", "Mike", "Sandra");
var users = names.stream().gather(zipWithIndex(User::new)).toList();
[User[index=0, name=Anna], User[index=1, name=Mike], User[index=2, name=Sandra]]
zipWithIndex(mapper, startIndex)
- zips current stream with an increasing index (beginning with startIndex), mapping function receives the index as the first argument.
import static io.github.jhspetersson.packrat.Packrat.zipWithIndex;
var names = List.of("Anna", "Mike", "Sandra");
var users = names.stream().gather(zipWithIndex(User::new, 10)).toList();
[User[index=10, name=Anna], User[index=11, name=Mike], User[index=12, name=Sandra]]
asGatherer(collector)
- provides the result of the supplied collector as a single element into the stream, effectively converts any Collector into a Gatherer
import static io.github.jhspetersson.packrat.Packrat.asGatherer;
var numbers = Stream.of(1, 2, 3, 4, 5);
var listOfCollectedList = numbers.gather(asGatherer(Collectors.toList())).toList();
System.out.println(listOfCollectedList);
[[1, 2, 3, 4, 5]]
Apache-2.0
Supported by JetBrains IDEA open source license.