@Test public void testHeadTail() { List<Integer> ints = IntStreamEx.range(1000).boxed().toList(); checkShortCircuitCollector("tail(0)", Arrays.asList(), 0, ints::stream, MoreCollectors.tail(0)); checkCollector("tail(1)", Arrays.asList(999), ints::stream, MoreCollectors.tail(1)); checkCollector("tail(2)", Arrays.asList(998, 999), ints::stream, MoreCollectors.tail(2)); checkCollector("tail(500)", ints.subList(500, 1000), ints::stream, MoreCollectors.tail(500)); checkCollector("tail(999)", ints.subList(1, 1000), ints::stream, MoreCollectors.tail(999)); checkCollector("tail(1000)", ints, ints::stream, MoreCollectors.tail(1000)); checkCollector("tail(MAX)", ints, ints::stream, MoreCollectors.tail(Integer.MAX_VALUE)); checkShortCircuitCollector("head(0)", Arrays.asList(), 0, ints::stream, MoreCollectors.head(0)); checkShortCircuitCollector( "head(1)", Arrays.asList(0), 1, ints::stream, MoreCollectors.head(1)); checkShortCircuitCollector( "head(2)", Arrays.asList(0, 1), 2, ints::stream, MoreCollectors.head(2)); checkShortCircuitCollector( "head(500)", ints.subList(0, 500), 500, ints::stream, MoreCollectors.head(500)); checkShortCircuitCollector( "head(999)", ints.subList(0, 999), 999, ints::stream, MoreCollectors.head(999)); checkShortCircuitCollector("head(1000)", ints, 1000, ints::stream, MoreCollectors.head(1000)); checkShortCircuitCollector( "head(MAX)", ints, 1000, ints::stream, MoreCollectors.head(Integer.MAX_VALUE)); checkShortCircuitCollector( "head(10000)", IntStreamEx.rangeClosed(1, 10000).boxed().toList(), 10000, () -> Stream.iterate(1, x -> x + 1), MoreCollectors.head(10000), true); }
@Test public void testMapping() { List<String> input = Arrays.asList("Capital", "lower", "Foo", "bar"); Collector<String, ?, Map<Boolean, Optional<Integer>>> collector = MoreCollectors.partitioningBy( str -> Character.isUpperCase(str.charAt(0)), MoreCollectors.mapping(String::length, MoreCollectors.first())); checkShortCircuitCollector( "mapping", new BooleanMap<>(Optional.of(7), Optional.of(5)), 2, input::stream, collector); Collector<String, ?, Map<Boolean, Optional<Integer>>> collectorLast = MoreCollectors.partitioningBy( str -> Character.isUpperCase(str.charAt(0)), MoreCollectors.mapping(String::length, MoreCollectors.last())); checkCollector( "last", new BooleanMap<>(Optional.of(3), Optional.of(3)), input::stream, collectorLast); input = Arrays.asList("Abc", "Bac", "Aac", "Abv", "Bbc", "Bgd", "Atc", "Bpv"); Map<Character, List<String>> expected = EntryStream.of('A', Arrays.asList("Abc", "Aac"), 'B', Arrays.asList("Bac", "Bbc")).toMap(); AtomicInteger cnt = new AtomicInteger(); Collector<String, ?, Map<Character, List<String>>> groupMap = Collectors.groupingBy( s -> s.charAt(0), MoreCollectors.mapping( x -> { cnt.incrementAndGet(); return x; }, MoreCollectors.head(2))); checkCollector("groupMap", expected, input::stream, groupMap); cnt.set(0); assertEquals(expected, input.stream().collect(groupMap)); assertEquals(4, cnt.get()); }
@Test public void testGroupingByWithDomain() { List<String> data = Arrays.asList("a", "foo", "test", "ququq", "bar", "blahblah"); Collector<String, ?, String> collector = MoreCollectors.collectingAndThen( MoreCollectors.groupingBy( String::length, IntStreamEx.range(10).boxed().toSet(), TreeMap::new, MoreCollectors.first()), Object::toString); checkShortCircuitCollector( "groupingWithDomain", "{0=Optional.empty, 1=Optional[a], 2=Optional.empty, 3=Optional[foo], 4=Optional[test], 5=Optional[ququq], " + "6=Optional.empty, 7=Optional.empty, 8=Optional[blahblah], 9=Optional.empty}", data.size(), data::stream, collector); Map<String, String> name2sex = new LinkedHashMap<>(); name2sex.put("Mary", "Girl"); name2sex.put("John", "Boy"); name2sex.put("James", "Boy"); name2sex.put("Lucie", "Girl"); name2sex.put("Fred", "Boy"); name2sex.put("Thomas", "Boy"); name2sex.put("Jane", "Girl"); name2sex.put("Ruth", "Girl"); name2sex.put("Melanie", "Girl"); Collector<Entry<String, String>, ?, Map<String, List<String>>> groupingBy = MoreCollectors.groupingBy( Entry::getValue, StreamEx.of("Girl", "Boy").toSet(), MoreCollectors.mapping(Entry::getKey, MoreCollectors.head(2))); AtomicInteger counter = new AtomicInteger(); Map<String, List<String>> map = EntryStream.of(name2sex).peek(c -> counter.incrementAndGet()).collect(groupingBy); assertEquals(Arrays.asList("Mary", "Lucie"), map.get("Girl")); assertEquals(Arrays.asList("John", "James"), map.get("Boy")); assertEquals(4, counter.get()); Collector<Entry<String, String>, ?, Map<String, String>> groupingByJoin = MoreCollectors.groupingBy( Entry::getValue, StreamEx.of("Girl", "Boy").toSet(), MoreCollectors.mapping( Entry::getKey, Joining.with(", ").maxChars(16).cutAfterDelimiter())); counter.set(0); Map<String, String> mapJoin = EntryStream.of(name2sex).peek(c -> counter.incrementAndGet()).collect(groupingByJoin); assertEquals("Mary, Lucie, ...", mapJoin.get("Girl")); assertEquals("John, James, ...", mapJoin.get("Boy")); assertEquals(7, counter.get()); }
@Test public void testHeadParallel() { List<Integer> expected = IntStreamEx.range(0, 2000, 2).boxed().toList(); List<Integer> expectedShort = Arrays.asList(0, 1); for (int i = 0; i < 1000; i++) { assertEquals( "#" + i, expectedShort, IntStreamEx.range(1000).boxed().parallel().collect(MoreCollectors.head(2))); assertEquals( "#" + i, expected, IntStreamEx.range(10000) .boxed() .parallel() .filter(x -> x % 2 == 0) .collect(MoreCollectors.head(1000))); } assertEquals( expectedShort, StreamEx.iterate(0, x -> x + 1).parallel().collect(MoreCollectors.head(2))); }
@Test public void testFlatMapping() { { Map<Integer, List<Integer>> expected = IntStreamEx.rangeClosed(1, 100) .boxed() .toMap(x -> IntStreamEx.rangeClosed(1, x).boxed().toList()); Collector<Integer, ?, Map<Integer, List<Integer>>> groupingBy = Collectors.groupingBy( Function.identity(), MoreCollectors.flatMapping( x -> IntStream.rangeClosed(1, x).boxed(), Collectors.toList())); checkCollector( "flatMappingSimple", expected, () -> IntStreamEx.rangeClosed(1, 100).boxed(), groupingBy); } Function<Entry<String, List<String>>, Stream<String>> valuesStream = e -> e.getValue() == null ? null : e.getValue().stream(); List<Entry<String, List<String>>> list = EntryStream.of( "a", Arrays.asList("bb", "cc", "dd"), "b", Arrays.asList("ee", "ff"), "c", null) .append("c", Arrays.asList("gg"), "b", null, "a", Arrays.asList("hh")) .toList(); { Map<String, List<String>> expected = EntryStream.of(list.stream()) .flatMapValues(l -> l == null ? null : l.stream()) .grouping(); checkCollector( "flatMappingCombine", expected, list::stream, Collectors.groupingBy( Entry::getKey, MoreCollectors.flatMapping(valuesStream, Collectors.toList()))); AtomicInteger openClose = new AtomicInteger(); Collector<Entry<String, List<String>>, ?, Map<String, List<String>>> groupingBy = Collectors.groupingBy( Entry::getKey, MoreCollectors.flatMapping( valuesStream.andThen( s -> { if (s == null) return null; openClose.incrementAndGet(); return s.onClose(openClose::decrementAndGet); }), Collectors.toList())); checkCollector( "flatMappingCombineClosed", expected, list::stream, MoreCollectors.collectingAndThen( groupingBy, res -> { assertEquals(0, openClose.get()); return res; })); boolean catched = false; try { Collector<Entry<String, List<String>>, ?, Map<String, List<String>>> groupingByException = Collectors.groupingBy( Entry::getKey, MoreCollectors.flatMapping( valuesStream.andThen( s -> { if (s == null) return null; openClose.incrementAndGet(); return s.onClose(openClose::decrementAndGet) .peek( e -> { if (e.equals("gg")) throw new IllegalArgumentException(e); }); }), Collectors.toList())); list.stream() .collect( MoreCollectors.collectingAndThen( groupingByException, res -> { assertEquals(0, openClose.get()); return res; })); } catch (IllegalArgumentException e1) { assertEquals("gg", e1.getMessage()); catched = true; } assertTrue(catched); } { Map<String, List<String>> expected = EntryStream.of( "a", Arrays.asList("bb"), "b", Arrays.asList("ee"), "c", Arrays.asList("gg")) .toMap(); Collector<Entry<String, List<String>>, ?, List<String>> headOne = MoreCollectors.flatMapping(valuesStream, MoreCollectors.head(1)); checkCollector( "flatMappingSubShort", expected, list::stream, Collectors.groupingBy(Entry::getKey, headOne)); checkShortCircuitCollector( "flatMappingShort", expected, 4, list::stream, MoreCollectors.groupingBy(Entry::getKey, StreamEx.of("a", "b", "c").toSet(), headOne)); AtomicInteger cnt = new AtomicInteger(); Collector<Entry<String, List<String>>, ?, List<String>> headPeek = MoreCollectors.flatMapping( valuesStream.andThen(s -> s == null ? null : s.peek(x -> cnt.incrementAndGet())), MoreCollectors.head(1)); assertEquals( expected, StreamEx.of(list).collect(Collectors.groupingBy(Entry::getKey, headPeek))); assertEquals(3, cnt.get()); cnt.set(0); assertEquals( expected, StreamEx.of(list) .collect( MoreCollectors.groupingBy( Entry::getKey, StreamEx.of("a", "b", "c").toSet(), headPeek))); assertEquals(3, cnt.get()); } { Map<String, List<String>> expected = EntryStream.of( "a", Arrays.asList("bb", "cc"), "b", Arrays.asList("ee", "ff"), "c", Arrays.asList("gg")) .toMap(); Collector<Entry<String, List<String>>, ?, List<String>> headTwo = MoreCollectors.flatMapping(valuesStream, MoreCollectors.head(2)); checkCollector( "flatMappingSubShort", expected, list::stream, Collectors.groupingBy(Entry::getKey, headTwo)); AtomicInteger openClose = new AtomicInteger(); boolean catched = false; try { Collector<Entry<String, List<String>>, ?, Map<String, List<String>>> groupingByException = Collectors.groupingBy( Entry::getKey, MoreCollectors.flatMapping( valuesStream.andThen( s -> { if (s == null) return null; openClose.incrementAndGet(); return s.onClose(openClose::decrementAndGet) .peek( e -> { if (e.equals("gg")) throw new IllegalArgumentException(e); }); }), MoreCollectors.head(2))); list.stream() .collect( MoreCollectors.collectingAndThen( groupingByException, res -> { assertEquals(0, openClose.get()); return res; })); } catch (IllegalArgumentException e1) { assertEquals("gg", e1.getMessage()); catched = true; } assertTrue(catched); } }