Skip to content

Commit

Permalink
Broader support for stream sizes
Browse files Browse the repository at this point in the history
+ Rename `exactSize(n)` to `sizeExactly(n)`
+ Add `sizeGreaterThan(n)`
+ Add `sizeGreaterThanOrEqualTo(n)`
+ Add `sizeLessThan(n)`
+ Add `sizeLessThanOrEqualTo(n)`
  • Loading branch information
tginsberg committed Jan 6, 2025
1 parent f09e29d commit b4cffeb
Show file tree
Hide file tree
Showing 5 changed files with 387 additions and 61 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
+ Implement `orderByFrequencyAscending()` and `orderByFrequencyDescending()`
+ Implement `movingProduct()` and `movingProductBy()`
+ Implement `movingSum()` and `movingSumBy()`
+ Functions, when used as arguments, should come last for consistency and to play nice with Kotlin (Fixes #64)
+ Remove `maxBy(fn)` and `minBy(fn)`, can be done with JDK methods trivially
+ Rename `exactSize()` to `sizeExactly()`
+ Implement `sizeLessThan`, `sizeLessThanOrEqualTo`, `sizeGreaterThan`, and `sizeGreaterThanOrEqualTo`
+ API Style - Functions, when used as arguments, should come last for consistency and to play nice with Kotlin (Fixes #64)

### 0.6.0
+ Implement `dropLast(n)`
Expand Down
63 changes: 60 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ implementation("com.ginsberg:gatherers4j:0.7.0")
| `dedupeConsecutiveBy(fn)` | Remove consecutive duplicates from a stream as returned by `fn` |
| `distinctBy(fn)` | Emit only distinct elements from the stream, as measured by `fn` |
| `dropLast(n)` | Keep all but the last `n` elements of the stream |
| `exactSize(n)` | Ensure the stream is exactly `n` elements long, or throw an `IllegalStateException` |
| `filterWithIndex(predicate)` | Filter the stream with the given `predicate`, which takes an `element` and its `index` |
| `grouping()` | Group consecute identical elements into lists |
| `groupingBy(fn)` | Group consecutive elements that are identical according to `fn` into lists |
Expand All @@ -51,6 +50,11 @@ implementation("com.ginsberg:gatherers4j:0.7.0")
| `reverse()` | Reverse the order of the stream |
| `shuffle()` | Shuffle the stream into a random order using the platform default `RandomGenerator` |
| `shuffle(rg)` | Shuffle the stream into a random order using the specified `RandomGenerator` |
| `sizeExactly(n)` | Ensure the stream is exactly `n` elements long, or throw an `IllegalStateException` |
| `sizeGreaterThan(n)` | Ensure the stream is greater than `n` elements long, or throw an `IllegalStateException` |
| `sizeGreaterThanOrEqualTo(n)` | Ensure the stream is greater than or equal to `n` elements long, or throw an `IllegalStateException` |
| `sizeLessThan(n)` | Ensure the stream is less than `n` elements long, or throw an `IllegalStateException` |
| `sizeLessThanOrEqualTo(n)` | Ensure the stream is less than or equal to `n` elements long, or throw an `IllegalStateException` |
| `throttle(amount, duration)` | Limit stream elements to `amount` elements over `duration`, pausing until a new `duration` period starts |
| `withIndex()` | Maps all elements of the stream as-is along with their 0-based index |
| `zipWith(iterable)` | Creates a stream of `Pair` objects whose values come from the input stream and argument iterable |
Expand Down Expand Up @@ -165,11 +169,64 @@ Stream.of("A", "B", "C", "D", "E")
```java
// Good

Stream.of("A", "B", "C").gather(Gatherers4j.exactSize(3)).toList();
Stream.of("A", "B", "C").gather(Gatherers4j.sizeExactly(3)).toList();
// ["A", "B", "C"]

// Bad
Stream.of("A").gather(Gatherers4j.exactSize(3)).toList();
Stream.of("A").gather(Gatherers4j.sizeExactly(3)).toList();
// IllegalStateException
```

#### Ensure the stream is greater than `n` elements long

```java
// Good

Stream.of("A", "B", "C").gather(Gatherers4j.sizeGreaterThan(2)).toList();
// ["A", "B", "C"]

// Bad
Stream.of("A", "B").gather(Gatherers4j.sizeGreaterThan(2)).toList();
// IllegalStateException
```

#### Ensure the stream is greater than or equal to `n` elements long

```java
// Good

Stream.of("A", "B").gather(Gatherers4j.sizeGreaterThanOrEqualTo(2)).toList();
// ["A", "B"]

// Bad
Stream.of("A").gather(Gatherers4j.sizeGreaterThanOrEqualTo(2)).toList();
// IllegalStateException
```

#### Ensure the stream is less than `n` elements long

```java
// Good

Stream.of("A").gather(Gatherers4j.sizeLessThan(2)).toList();
// ["A"]

// Bad
Stream.of("A", "B").gather(Gatherers4j.sizeLessThan(2)).toList();
// IllegalStateException
```


#### Ensure the stream is less than or equal to `n` elements long

```java
// Good

Stream.of("A", "B").gather(Gatherers4j.sizeLessThanOrEqualTo(2)).toList();
// ["A", "B"]

// Bad
Stream.of("A", "B", "C").gather(Gatherers4j.sizeLessThanOrEqualTo(2)).toList();
// IllegalStateException
```

Expand Down
84 changes: 64 additions & 20 deletions src/main/java/com/ginsberg/gatherers4j/Gatherers4j.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,11 @@ public abstract class Gatherers4j {
return new DropLastGatherer<>(count);
}

/// Ensure the input stream is exactly `size` elements long, and emit all elements if so.
/// If not, throw an `IllegalStateException`.
///
/// @param size Exact number of elements the stream must have
/// @param <INPUT> Type of elements in both the input and output streams
/// @return A non-null `SizeGatherer`
/// @throws IllegalStateException when the input stream is not exactly `size` elements long
public static <INPUT extends @Nullable Object> SizeGatherer<INPUT> exactSize(final long size) {
return new SizeGatherer<>(size);
}

/// Filter a stream according to the given `predicate`, which takes both the item being examined,
/// and its index.
///
/// @param predicate A non-null `BiPredicate<Long,INPUT>` where the `Long` is the zero-based index of the element
/// being filtered, and the `INPUT` is the element itself.
/// being filtered, and the `INPUT` is the element itself.
/// @param <INPUT> Type of elements in the input stream
/// @return A non-null `FilteringWithIndexGatherer`
public static <INPUT extends @Nullable Object> FilteringWithIndexGatherer<INPUT> filterWithIndex(
Expand Down Expand Up @@ -181,7 +170,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
///
/// @param windowSize The trailing number of elements to multiply, must be greater than 1.
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the moving product calculation
/// in the moving product calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalMovingProductGatherer`
public static <INPUT extends @Nullable Object> BigDecimalMovingProductGatherer<INPUT> movingProductBy(
Expand All @@ -205,7 +194,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
///
/// @param windowSize The trailing number of elements to multiply, must be greater than 1.
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the moving sum calculation
/// in the moving sum calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalMovingSumGatherer`
public static <INPUT extends @Nullable Object> BigDecimalMovingSumGatherer<INPUT> movingSumBy(
Expand Down Expand Up @@ -287,7 +276,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
/// objects mapped from a `Stream<BigDecimal>` via a `mappingFunction`.
///
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the standard deviation calculation
/// in the standard deviation calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalStandardDeviationGatherer`
public static <INPUT extends @Nullable Object> BigDecimalStandardDeviationGatherer<INPUT> runningPopulationStandardDeviationBy(
Expand All @@ -310,7 +299,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
/// from a `Stream<INPUT>` via a `mappingFunction`.
///
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the product calculation
/// in the product calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalProductGatherer`
public static <INPUT extends @Nullable Object> BigDecimalProductGatherer<INPUT> runningProductBy(
Expand All @@ -333,7 +322,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
/// from a `Stream<INPUT>` via a `mappingFunction`.
///
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the standard deviation calculation
/// in the standard deviation calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalStandardDeviationGatherer`
public static <INPUT extends @Nullable Object> BigDecimalStandardDeviationGatherer<INPUT> runningSampleStandardDeviationBy(
Expand All @@ -356,7 +345,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
/// from a `Stream<INPUT>` via a `mappingFunction`.
///
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the running sum calculation
/// in the running sum calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalSumGatherer`
public static <INPUT extends @Nullable Object> BigDecimalSumGatherer<INPUT> runningSumBy(
Expand Down Expand Up @@ -399,7 +388,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
/// the given function. This is useful when paired with the `withOriginal` function.
///
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the running average calculation
/// in the running average calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalSimpleAverageGatherer`
public static <INPUT extends @Nullable Object> BigDecimalSimpleAverageGatherer<INPUT> simpleRunningAverageBy(
Expand All @@ -422,7 +411,7 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
///
/// @param windowSize The number of elements to average, must be greater than 1.
/// @param mappingFunction A function to map `<INPUT>` objects to `BigDecimal`, the results of which will be used
/// in the moving average calculation
/// in the moving average calculation
/// @param <INPUT> Type of elements in the input stream, to be remapped to `BigDecimal` by the `mappingFunction`
/// @return A non-null `BigDecimalSimpleMovingAverageGatherer`
public static <INPUT extends @Nullable Object> BigDecimalSimpleMovingAverageGatherer<INPUT> simpleMovingAverageBy(
Expand All @@ -432,6 +421,61 @@ public static <INPUT> LastGatherer<INPUT> last(final int count) {
return new BigDecimalSimpleMovingAverageGatherer<>(windowSize, mappingFunction);
}

/// Ensure the input stream is exactly `size` elements long, and emit all elements if so.
/// If not, throw an `IllegalStateException`.
///
/// @param size Exact number of elements the stream must have
/// @param <INPUT> Type of elements in both the input and output streams
/// @return A non-null `SizeGatherer`
/// @throws IllegalStateException when the input stream is not exactly `size` elements long
public static <INPUT extends @Nullable Object> SizeGatherer<INPUT> sizeExactly(final long size) {
return new SizeGatherer<>(SizeGatherer.Operation.Equal, size);
}

/// Ensure the input stream is greater than `size` elements long, and emit all elements if so.
/// If not, throw an `IllegalStateException`.
///
/// @param size The size the stream must be longer than
/// @param <INPUT> Type of elements in both the input and output streams
/// @return A non-null `SizeGatherer`
/// @throws IllegalStateException when the input stream is not exactly `size` elements long
public static <INPUT extends @Nullable Object> SizeGatherer<INPUT> sizeGreaterThan(final long size) {
return new SizeGatherer<>(SizeGatherer.Operation.GreaterThan, size);
}

/// Ensure the input stream is greater than or equal to `size` elements long, and emit all elements if so.
/// If not, throw an `IllegalStateException`.
///
/// @param size The minimum size of the stream
/// @param <INPUT> Type of elements in both the input and output streams
/// @return A non-null `SizeGatherer`
/// @throws IllegalStateException when the input stream is not exactly `size` elements long
public static <INPUT extends @Nullable Object> SizeGatherer<INPUT> sizeGreaterThanOrEqualTo(final long size) {
return new SizeGatherer<>(SizeGatherer.Operation.GreaterThanOrEqualTo, size);
}

/// Ensure the input stream is less than `size` elements long, and emit all elements if so.
/// If not, throw an `IllegalStateException`.
///
/// @param size The size the stream must be shorter than
/// @param <INPUT> Type of elements in both the input and output streams
/// @return A non-null `SizeGatherer`
/// @throws IllegalStateException when the input stream is not exactly `size` elements long
public static <INPUT extends @Nullable Object> SizeGatherer<INPUT> sizeLessThan(final long size) {
return new SizeGatherer<>(SizeGatherer.Operation.LessThan, size);
}

/// Ensure the input stream is less than or equal to `size` elements long, and emit all elements if so.
/// If not, throw an `IllegalStateException`.
///
/// @param size The maximum size the stream
/// @param <INPUT> Type of elements in both the input and output streams
/// @return A non-null `SizeGatherer`
/// @throws IllegalStateException when the input stream is not exactly `size` elements long
public static <INPUT extends @Nullable Object> SizeGatherer<INPUT> sizeLessThanOrEqualTo(final long size) {
return new SizeGatherer<>(SizeGatherer.Operation.LessThanOrEqualTo, size);
}

/// Limit the number of elements in the stream to some number per period. When the limit is reached,
/// consumption is paused until a new period starts and the count resets.
///
Expand Down
Loading

0 comments on commit b4cffeb

Please sign in to comment.