Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broader support for stream sizes #69

Merged
merged 1 commit into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading