diff --git a/stream-core/src/main/java/org/dromara/streamquery/stream/core/stream/collector/Collective.java b/stream-core/src/main/java/org/dromara/streamquery/stream/core/stream/collector/Collective.java index 4b414dac578553328c6aeca4851d6ded16734f2c..6401ea3e9d2604e3976af839940b6d5f4af02d24 100644 --- a/stream-core/src/main/java/org/dromara/streamquery/stream/core/stream/collector/Collective.java +++ b/stream-core/src/main/java/org/dromara/streamquery/stream/core/stream/collector/Collective.java @@ -116,6 +116,46 @@ public class Collective { CH_ID); } + /** + * Constructs a collector that retrieves a sublist from the input elements. + * + * @param limit The maximum length of the returned list. If null, returns all remaining elements. + * @param The type of the input elements. + * @return a {@code Collector} that collects all input elements into a {@code List}, representing a subset of the original collection. + */ + public static Collector> limiting(int limit) { + return subList(null, limit); + } + + /** + * Constructs a collector that retrieves a sublist from the input elements. + * + * @param skip The number of elements to skip, ignore the first few elements of the collection. If null, no elements are skipped. + * @param The type of the input elements. + * @return a {@code Collector} that collects all input elements into a {@code List}, representing a subset of the original collection. + */ + public static Collector> skipping(int skip) { + return subList(skip, null); + } + + /** + * Constructs a collector that retrieves a sublist from the input elements. + * + * @param skip The number of elements to skip, ignore the first few elements of the collection. If null, no elements are skipped. + * @param limit The maximum length of the returned list. If null, returns all remaining elements. + * @param The type of the input elements. + * @return a {@code Collector} that collects all input elements into a {@code List}, representing a subset of the original collection. + */ + public static Collector> subList(Integer skip, Integer limit) { + Integer offset = Opp.of(skip).orElse(0); + return mapping(Function.identity(), collectingAndThen(toList(), list -> { + int size = list.size(); + int fromIndex = Math.min(size, offset); + int toIndex = Opp.of(limit).map(l -> Math.min(fromIndex + l, size)).orElse(size); + return list.subList(fromIndex, toIndex); + })); + } + /** * Returns a {@code Collector} that accumulates the input elements into a new {@code Set}. There * are no guarantees on the type, mutability, serializability, or thread-safety of the {@code Set} diff --git a/stream-core/src/test/java/org/dromara/streamquery/stream/core/stream/collector/CollectiveTest.java b/stream-core/src/test/java/org/dromara/streamquery/stream/core/stream/collector/CollectiveTest.java index 307b00eb7010990f3b0af15135e2a186a1afdfc6..3a4a1282ab3a1c2cbf10ac191c9c650fd65ed759 100644 --- a/stream-core/src/test/java/org/dromara/streamquery/stream/core/stream/collector/CollectiveTest.java +++ b/stream-core/src/test/java/org/dromara/streamquery/stream/core/stream/collector/CollectiveTest.java @@ -16,6 +16,7 @@ */ package org.dromara.streamquery.stream.core.stream.collector; +import org.dromara.streamquery.stream.core.lambda.LambdaInvokeException; import org.dromara.streamquery.stream.core.stream.Steam; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -62,6 +63,67 @@ class CollectiveTest { .isEmpty()); } + @Test + void testLimiting() { + List list = Arrays.asList(0, 0, 0, 1, 1, 1, 1); + Map> map = list.stream().collect(groupingBy(Function.identity(), limiting(0))); + Assertions.assertEquals(2, map.size()); + Assertions.assertEquals(0, map.get(0).size()); + Assertions.assertEquals(0, map.get(1).size()); + + Map> map1 = list.stream().collect(groupingBy(Function.identity(), limiting(2))); + Assertions.assertEquals(2, map1.size()); + Assertions.assertEquals(2, map1.get(0).size()); + Assertions.assertEquals(2, map1.get(1).size()); + + Map> map2 = list.stream().collect(groupingBy(Function.identity(), limiting(10))); + Assertions.assertEquals(2, map2.size()); + Assertions.assertEquals(3, map2.get(0).size()); + Assertions.assertEquals(4, map2.get(1).size()); + + Assertions.assertThrows(LambdaInvokeException.class, () -> list.stream().collect(groupingBy(Function.identity(), limiting(-1)))); + } + + @Test + void testSkipping() { + List list = Arrays.asList(0, 0, 0, 1, 1, 1, 1); + Map> map = list.stream().collect(groupingBy(Function.identity(), skipping(2))); + Assertions.assertEquals(2, map.size()); + Assertions.assertEquals(1, map.get(0).size()); + Assertions.assertEquals(2, map.get(1).size()); + + Map> map1 = list.stream().collect(groupingBy(Function.identity(), skipping(10))); + Assertions.assertEquals(2, map1.size()); + Assertions.assertEquals(0, map1.get(0).size()); + Assertions.assertEquals(0, map1.get(1).size()); + + Map> map2 = list.stream().collect(groupingBy(Function.identity(), skipping(0))); + Assertions.assertEquals(2, map2.size()); + Assertions.assertEquals(3, map2.get(0).size()); + Assertions.assertEquals(4, map2.get(1).size()); + + Assertions.assertThrows(LambdaInvokeException.class, () -> list.stream().collect(groupingBy(Function.identity(), skipping(-1)))); + } + + @Test + void testSubList() { + List list = Arrays.asList(0, 0, 1, 1, 1, 2, 2, 2, 2); + Map> map1 = list.stream().collect(groupingBy(Function.identity(), subList(1, 2))); + Assertions.assertEquals(3, map1.size()); + Assertions.assertEquals(1, map1.get(0).size()); + Assertions.assertEquals(2, map1.get(1).size()); + Assertions.assertEquals(2, map1.get(2).size()); + + Map> map2 = list.stream().collect(groupingBy(Function.identity(), subList(10, 2))); + Assertions.assertEquals(3, map2.size()); + Assertions.assertEquals(0, map2.get(0).size()); + Assertions.assertEquals(0, map2.get(1).size()); + Assertions.assertEquals(0, map2.get(2).size()); + + Assertions.assertThrows(LambdaInvokeException.class, () -> list.stream().collect(groupingBy(Function.identity(), subList(-1, 2)))); + Assertions.assertThrows(LambdaInvokeException.class, () -> list.stream().collect(groupingBy(Function.identity(), subList(1, -1)))); + } + @Test void testFlatMapping() { List actual =