Skip to content

Instantly share code, notes, and snippets.

@pfichtner
Last active February 1, 2023 21:33
Show Gist options
  • Select an option

  • Save pfichtner/db497fb0582c63d2268d2f62b22174d1 to your computer and use it in GitHub Desktop.

Select an option

Save pfichtner/db497fb0582c63d2268d2f62b22174d1 to your computer and use it in GitHub Desktop.
Partition a Stream of objects (e.g. Strings) into a Stream of Lists based on a separator in the Stream
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.toList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
class PartitionBySeparator {
Predicate<String> startWithDashes = s -> s.startsWith("---");
@Test
void canPartitionBySeparatorWithTrailingSeparator() {
var in = Stream.of("A", "B", "-----", "1", "2", "3", "-----", "X", "-----");
var expected = List.of(List.of("A", "B"), List.of("1", "2", "3"), List.of("X"));
Stream<List<String>> partitioned = partition(in, startWithDashes, false);
assertEquals(expected, partitioned.collect(toList()));
}
@Test
void canPartitionBySeparatorWithTrailingSeparatorWithSeparatorIncluded() {
var in = Stream.of("A", "B", "-----", "1", "2", "3", "-----", "X", "-----");
var expected = List.of(List.of("A", "B", "-----"), List.of("1", "2", "3", "-----"), List.of("X", "-----"));
Stream<List<String>> partitioned = partition(in, startWithDashes, true);
assertEquals(expected, partitioned.collect(toList()));
}
@Test
void canPartitionBySeparatorWithoutTrailingSeparator() {
var in = Stream.of("A", "B", "-----", "1", "2", "3", "-----", "X");
var expected = List.of(List.of("A", "B"), List.of("1", "2", "3"), List.of("X"));
Stream<List<String>> partitioned = partition(in, startWithDashes, false);
assertEquals(expected, partitioned.collect(toList()));
}
@Test
void canPartitionBySeparatorWithoutTrailingSeparatorWithSeparatorIncluded() {
var in = Stream.of("A", "B", "-----", "1", "2", "3", "-----", "X");
var expected = List.of(List.of("A", "B", "-----"), List.of("1", "2", "3", "-----"), List.of("X"));
Stream<List<String>> partitioned = partition(in, startWithDashes, true);
assertEquals(expected, partitioned.collect(toList()));
}
private static Stream<List<String>> partition(Stream<String> stream, Predicate<String> predicate,
boolean withSeparator) {
return stream.reduce(new ArrayList<>(), separateBy(predicate, ArrayList::new, withSeparator), combineLists())
.stream().filter(not(List<String>::isEmpty));
}
private static <T> BiFunction<List<List<T>>, T, List<List<T>>> separateBy(Predicate<T> predicate,
Supplier<List<T>> supplier, boolean withSeparator) {
return (acc, elem) -> {
if (predicate.test(elem)) {
if (withSeparator) {
addToLastList(acc, elem);
}
addNewList(acc, supplier);
} else {
if (acc.isEmpty()) {
addNewList(acc, supplier);
}
addToLastList(acc, elem);
}
return acc;
};
}
private static <T> void addNewList(List<List<T>> outer, Supplier<List<T>> supplier) {
outer.add(supplier.get());
}
private static <T> void addToLastList(List<List<T>> acc, T elem) {
acc.get(acc.size() - 1).add(elem);
}
private static <T> BinaryOperator<List<List<T>>> combineLists() {
return (l1, l2) -> {
l1.addAll(l2);
return l1;
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment