diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:08:27 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:08:27 +0200 |
| commit | c9b6b9a5ca082fe7c1b6f58d7713f785a9eb6a5c (patch) | |
| tree | 3e4f42f93c7ae89a364e4d51fff6e5cec4e55fa9 /graphs/java/seq | |
add: graphs et rushs
Diffstat (limited to 'graphs/java/seq')
| -rw-r--r-- | graphs/java/seq/.gitignore | 38 | ||||
| -rw-r--r-- | graphs/java/seq/pom.xml | 133 | ||||
| -rw-r--r-- | graphs/java/seq/src/main/java/fr/epita/assistants/seq/ExtendedStream.java | 204 | ||||
| -rw-r--r-- | graphs/java/seq/src/main/java/fr/epita/assistants/seq/Seq.java | 413 | ||||
| -rw-r--r-- | graphs/java/seq/src/test/java/fr/epita/assistants/seq/ExtendedStreamTest.java | 244 |
5 files changed, 1032 insertions, 0 deletions
diff --git a/graphs/java/seq/.gitignore b/graphs/java/seq/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/graphs/java/seq/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store
\ No newline at end of file diff --git a/graphs/java/seq/pom.xml b/graphs/java/seq/pom.xml new file mode 100644 index 0000000..46ba851 --- /dev/null +++ b/graphs/java/seq/pom.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>fr.epita.assistants</groupId> + <artifactId>seq</artifactId> + <version>1.0</version> + + <properties> + <versions.java>21</versions.java> + <versions.junit>5.9.1</versions.junit> + <versions.maven-compiler-plugin>3.13.0</versions.maven-compiler-plugin> + <versions.maven-surefire-plugin>3.5.0</versions.maven-surefire-plugin> + <versions.maven-jar-plugin>3.1.1</versions.maven-jar-plugin> + <versions.maven-install-plugin>3.1.0</versions.maven-install-plugin> + + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + + <surefire.reportsDirectory>${project.build.directory}/surefire-reports</surefire.reportsDirectory> + </properties> + + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <version>${versions.junit}</version> + </dependency> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit-platform</artifactId> + <version>${versions.maven-surefire-plugin}</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-compat</artifactId> + <version>3.9.8</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>3.9.8</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-core</artifactId> + <version>3.8.1</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-monitor</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-utils</artifactId> + <version>3.0.24</version> + </dependency> + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-filtering</artifactId> + <version>3.3.2</version> + </dependency> + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-interpolation</artifactId> + <version>1.13</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-profile</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-artifact-manager</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-registry</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-repository-metadata</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>classworlds</groupId> + <artifactId>classworlds</artifactId> + <version>1.1</version> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-commons</artifactId> + <version>1.9.3</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${versions.maven-compiler-plugin}</version> + <configuration> + <source>${versions.java}</source> + <target>${versions.java}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <version>${versions.maven-install-plugin}</version> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>${versions.maven-surefire-plugin}</version> + <configuration> + <reportsDirectory>${surefire.reportsDirectory}</reportsDirectory> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/graphs/java/seq/src/main/java/fr/epita/assistants/seq/ExtendedStream.java b/graphs/java/seq/src/main/java/fr/epita/assistants/seq/ExtendedStream.java new file mode 100644 index 0000000..0ba5f6a --- /dev/null +++ b/graphs/java/seq/src/main/java/fr/epita/assistants/seq/ExtendedStream.java @@ -0,0 +1,204 @@ +package fr.epita.assistants.seq; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +/** + * Extends the {@link Stream} interface, adding some very strangely lacking useful methods. + * You should use the Forwarding-Interface pattern. + * <p> + * The use of infinite, unordered or parallel stream in this implementation will + * not be tested. + * + * @param <ELEMENT_TYPE> the type of stream. + */ +@SuppressWarnings("unused") +public interface ExtendedStream<ELEMENT_TYPE> extends Stream<ELEMENT_TYPE> { + + + /** + * Creates a map out of the stream. + * In case of duplicate keys, the latest element in the original stream will overwrite the one(s) in place. + * + * @param keyMapper mapping function to extract map keys. + * @param <KEY_TYPE> the expected type of key. + * @return the created map. + */ + <KEY_TYPE> Map<KEY_TYPE, ELEMENT_TYPE> + toMap(final Function<ELEMENT_TYPE, KEY_TYPE> keyMapper); + + /** + * Creates a map out of the stream. + * In case of key duplicates, the latest element in the original stream will overwrite the one(s) in place. + * + * @param map the map to fill/update. + * @param keyMapper mapping function to extract map keys. + * @param valueMapper mapping function to extract map values. + * @param <KEY_TYPE> the expected type of key. + * @param <VALUE_TYPE> the expected type of value. + * @param <MAP_TYPE> the complete return type. + * @return the created map. + */ + <KEY_TYPE, VALUE_TYPE, MAP_TYPE extends Map<KEY_TYPE, VALUE_TYPE>> + MAP_TYPE toMap(final MAP_TYPE map, + final Function<ELEMENT_TYPE, KEY_TYPE> keyMapper, + final Function<ELEMENT_TYPE, VALUE_TYPE> valueMapper); + + /** + * Creates a map out of the stream. + * In case of duplicate keys, the latest element in the original stream will overwrite the one(s) in place. + * + * @param keyMapper mapping function to extract map keys. + * @param valueMapper mapping function to extract map values. + * @param <KEY_TYPE> the expected type of key. + * @param <VALUE_TYPE> the expected type of value. + * @return the created map. + */ + <KEY_TYPE, VALUE_TYPE> + Map<KEY_TYPE, VALUE_TYPE> toMap(final Function<ELEMENT_TYPE, KEY_TYPE> keyMapper, + final Function<ELEMENT_TYPE, VALUE_TYPE> valueMapper); + + /** + * Converts the stream to a list. + * + * @return the created list. + */ + List<ELEMENT_TYPE> toList(); + + /** + * Dumps the content of the stream to the given list. + * + * @param list the list to dump values to. + * @param <LIST> the exact type of list. + * @return the updated list. + */ + <LIST extends List<ELEMENT_TYPE>> LIST toList(final LIST list); + + /** + * Converts the stream to a set. + * + * @return the built set. + */ + Set<ELEMENT_TYPE> toSet(); + + /** + * Dumps the content of the stream to the given set. + * + * @param set the set to update + * @param <SET> the set type. + * @return the updated set. + */ + <SET extends Set<ELEMENT_TYPE>> SET toSet(final SET set); + + /** + * Creates a stream of pairs of the content of the stream and values produced by a supplier. + * + * @param supplier the value supplier. + * @param <ASSOCIATED_TYPE> the type of associated values. + * @return the built stream. + */ + <ASSOCIATED_TYPE> + ExtendedStream<Pair<ELEMENT_TYPE, ASSOCIATED_TYPE>> associate(final Supplier<ASSOCIATED_TYPE> supplier); + + /** + * Creates a stream of pairs of the content of the stream and values produces by another stream. + * Once any of the two streams is closed, the produced stream is complete, regardless of potential values remaining + * in the other stream. + * + * @param supplier the value supplier. + * @param <ASSOCIATED_TYPE> the type of associated values. + * @return the built stream. + */ + <ASSOCIATED_TYPE> + ExtendedStream<Pair<ELEMENT_TYPE, ASSOCIATED_TYPE>> associate(final Stream<ASSOCIATED_TYPE> supplier); + + /** + * Prints the element of the stream on the standard output. + * + * @return this. + */ + ExtendedStream<ELEMENT_TYPE> print(); + + /** + * Adds the content of the given stream to the current stream and returns it as a new one. + * + * @param stream the stream to add. + * @return a new stream containing the current one then the given one. + */ + ExtendedStream<ELEMENT_TYPE> plus(final Stream<ELEMENT_TYPE> stream); + + /** + * Builds a string by joining the string representation of all contained values, interspersed with the given string + * delimiter. + * + * @param delimiter the delimiter string. + * @return the built {@link String}. + */ + String join(final String delimiter); + + /** + * Builds a string by joining the string representation of all contained values. + * + * @return the built {@link String}. + */ + String join(); + + /** + * Builds a pair of streams by partitioning the current one using the given pivot function. + * + * @param pivot the function to segregate the values of the given stream. + * @param <KEY_TYPE> type of partition key. + * @return the pair of created streams. + */ + <KEY_TYPE> + ExtendedStream<Pair<KEY_TYPE, ExtendedStream<ELEMENT_TYPE>>> + partition(final Function<ELEMENT_TYPE, KEY_TYPE> pivot); + + /** + * A utility class representing a pair. + * + * @param <FIRST_TYPE> the first value type. + * @param <SECOND_TYPE> the second value type. + */ + @SuppressWarnings("WeakerAccess") + class Pair<FIRST_TYPE, SECOND_TYPE> { + /** + * The first value. + */ + public final FIRST_TYPE first; + + /** + * The second value. + */ + public final SECOND_TYPE second; + + /** + * Default CTor. + * + * @param first value of the same name. + * @param second value of the same name. + */ + public Pair(final FIRST_TYPE first, final SECOND_TYPE second) { + this.first = first; + this.second = second; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) return false; + if (!obj.getClass().equals(Pair.class)) return false; + final Pair pair = (Pair) obj; + return Objects.equals(first, pair.first) && Objects.equals(second, pair.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + } +} diff --git a/graphs/java/seq/src/main/java/fr/epita/assistants/seq/Seq.java b/graphs/java/seq/src/main/java/fr/epita/assistants/seq/Seq.java new file mode 100644 index 0000000..31e5cab --- /dev/null +++ b/graphs/java/seq/src/main/java/fr/epita/assistants/seq/Seq.java @@ -0,0 +1,413 @@ +package fr.epita.assistants.seq; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +public interface Seq<ELEMENT_TYPE> extends ExtendedStream<ELEMENT_TYPE> { + Stream<ELEMENT_TYPE> giveStream(); + + static <ELEMENT_TYPE> Seq<ELEMENT_TYPE> of(Stream<ELEMENT_TYPE> stream) { + return () -> stream; + } + + static <ELEMENT_TYPE> Seq<ELEMENT_TYPE> of(List<ELEMENT_TYPE> list) { + return list::stream; + } + + static <ELEMENT_TYPE> Seq<ELEMENT_TYPE> of(ELEMENT_TYPE... values) { + List<ELEMENT_TYPE> vals = new ArrayList<>(Arrays.asList(values)); + return vals::stream; + } + + /** + * Creates a map out of the stream. + * In case of duplicate keys, the latest element in the original stream will overwrite the one(s) in place. + * + * @param keyMapper mapping function to extract map keys. + * @param <KEY_TYPE> the expected type of key. + * @return the created map. + */ + default <KEY_TYPE> Map<KEY_TYPE, ELEMENT_TYPE> + toMap(final Function<ELEMENT_TYPE, KEY_TYPE> keyMapper) { + Map<KEY_TYPE, ELEMENT_TYPE> map = new HashMap<>(); + giveStream().forEach(e -> map.put(keyMapper.apply(e), e)); + return map; + } + + /** + * Creates a map out of the stream. + * In case of key duplicates, the latest element in the original stream will overwrite the one(s) in place. + * + * @param map the map to fill/update. + * @param keyMapper mapping function to extract map keys. + * @param valueMapper mapping function to extract map values. + * @param <KEY_TYPE> the expected type of key. + * @param <VALUE_TYPE> the expected type of value. + * @param <MAP_TYPE> the complete return type. + * @return the created map. + */ + default <KEY_TYPE, VALUE_TYPE, MAP_TYPE extends Map<KEY_TYPE, VALUE_TYPE>> + MAP_TYPE toMap(final MAP_TYPE map, + final Function<ELEMENT_TYPE, KEY_TYPE> keyMapper, + final Function<ELEMENT_TYPE, VALUE_TYPE> valueMapper) { + giveStream().forEach(e -> map.put(keyMapper.apply(e), valueMapper.apply(e))); + return map; + } + + /** + * Creates a map out of the stream. + * In case of duplicate keys, the latest element in the original stream will overwrite the one(s) in place. + * + * @param keyMapper mapping function to extract map keys. + * @param valueMapper mapping function to extract map values. + * @param <KEY_TYPE> the expected type of key. + * @param <VALUE_TYPE> the expected type of value. + * @return the created map. + */ + default <KEY_TYPE, VALUE_TYPE> + Map<KEY_TYPE, VALUE_TYPE> toMap(final Function<ELEMENT_TYPE, KEY_TYPE> keyMapper, + final Function<ELEMENT_TYPE, VALUE_TYPE> valueMapper) { + Map<KEY_TYPE, VALUE_TYPE> map = new HashMap<>(); + giveStream().forEach(e -> map.put(keyMapper.apply(e), valueMapper.apply(e))); + return map; + } + + @Override + public default Stream<ELEMENT_TYPE> filter(Predicate<? super ELEMENT_TYPE> predicate) { + return giveStream().filter(predicate); + } + + @Override + public default <R> Stream<R> map(Function<? super ELEMENT_TYPE, ? extends R> mapper) { + return giveStream().map(mapper); + } + + @Override + public default IntStream mapToInt(ToIntFunction<? super ELEMENT_TYPE> mapper) { + return giveStream().mapToInt(mapper); + } + + @Override + public default LongStream mapToLong(ToLongFunction<? super ELEMENT_TYPE> mapper) { + return giveStream().mapToLong(mapper); + } + + @Override + public default DoubleStream mapToDouble(ToDoubleFunction<? super ELEMENT_TYPE> mapper) { + return giveStream().mapToDouble(mapper); + } + + @Override + public default <R> Stream<R> flatMap(Function<? super ELEMENT_TYPE, ? extends Stream<? extends R>> mapper) { + return giveStream().flatMap(mapper); + } + + @Override + public default IntStream flatMapToInt(Function<? super ELEMENT_TYPE, ? extends IntStream> mapper) { + return giveStream().flatMapToInt(mapper); + } + + @Override + public default LongStream flatMapToLong(Function<? super ELEMENT_TYPE, ? extends LongStream> mapper) { + return giveStream().flatMapToLong(mapper); + } + + @Override + public default DoubleStream flatMapToDouble(Function<? super ELEMENT_TYPE, ? extends DoubleStream> mapper) { + return giveStream().flatMapToDouble(mapper); + } + + @Override + public default Stream<ELEMENT_TYPE> distinct() { + return giveStream().distinct(); + } + + @Override + public default Stream<ELEMENT_TYPE> sorted() { + return giveStream().sorted(); + } + + @Override + public default Stream<ELEMENT_TYPE> sorted(Comparator<? super ELEMENT_TYPE> comparator) { + return giveStream().sorted(comparator); + } + + @Override + public default Stream<ELEMENT_TYPE> peek(Consumer<? super ELEMENT_TYPE> action) { + return giveStream().peek(action); + } + + @Override + public default Stream<ELEMENT_TYPE> limit(long maxSize) { + return giveStream().limit(maxSize); + } + + @Override + public default Stream<ELEMENT_TYPE> skip(long n) { + return giveStream().skip(n); + } + + @Override + public default void forEach(Consumer<? super ELEMENT_TYPE> action) { + giveStream().forEach(action); + } + + @Override + public default void forEachOrdered(Consumer<? super ELEMENT_TYPE> action) { + giveStream().forEachOrdered(action); + } + + @Override + public default Object[] toArray() { + return giveStream().toArray(); + } + + @Override + public default <A> A[] toArray(IntFunction<A[]> generator) { + return giveStream().toArray(generator); + } + + @Override + public default ELEMENT_TYPE reduce(ELEMENT_TYPE identity, BinaryOperator<ELEMENT_TYPE> accumulator) { + return giveStream().reduce(identity, accumulator); + } + + @Override + public default Optional<ELEMENT_TYPE> reduce(BinaryOperator<ELEMENT_TYPE> accumulator) { + return giveStream().reduce(accumulator); + } + + @Override + public default <U> U reduce(U identity, BiFunction<U, ? super ELEMENT_TYPE, U> accumulator, BinaryOperator<U> combiner) { + return giveStream().reduce(identity, accumulator, combiner); + } + + @Override + public default <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super ELEMENT_TYPE> accumulator, BiConsumer<R, R> combiner) { + return giveStream().collect(supplier, accumulator, combiner); + } + + @Override + public default <R, A> R collect(Collector<? super ELEMENT_TYPE, A, R> collector) { + return giveStream().collect(collector); + } + + /** + * Converts the stream to a list. + * + * @return the created list. + */ + default List<ELEMENT_TYPE> toList() { + return giveStream().toList(); + } + + @Override + public default Optional<ELEMENT_TYPE> min(Comparator<? super ELEMENT_TYPE> comparator) { + return giveStream().min(comparator); + } + + @Override + public default Optional<ELEMENT_TYPE> max(Comparator<? super ELEMENT_TYPE> comparator) { + return giveStream().max(comparator); + } + + @Override + public default long count() { + return giveStream().count(); + } + + @Override + public default boolean anyMatch(Predicate<? super ELEMENT_TYPE> predicate) { + return giveStream().anyMatch(predicate); + } + + @Override + public default boolean allMatch(Predicate<? super ELEMENT_TYPE> predicate) { + return giveStream().allMatch(predicate); + } + + @Override + public default boolean noneMatch(Predicate<? super ELEMENT_TYPE> predicate) { + return giveStream().noneMatch(predicate); + } + + @Override + public default Optional<ELEMENT_TYPE> findFirst() { + return giveStream().findFirst(); + } + + @Override + public default Optional<ELEMENT_TYPE> findAny() { + return giveStream().findAny(); + } + + /** + * Dumps the content of the stream to the given list. + * + * @param list the list to dump values to. + * @param <LIST> the exact type of list. + * @return the updated list. + */ + default <LIST extends List<ELEMENT_TYPE>> LIST toList(final LIST list) { + giveStream().forEach(list::add); + return list; + } + + /** + * Converts the stream to a set. + * + * @return the built set. + */ + default Set<ELEMENT_TYPE> toSet() { + return giveStream().collect(Collectors.toSet()); + } + + /** + * Dumps the content of the stream to the given set. + * + * @param set the set to update + * @param <SET> the set type. + * @return the updated set. + */ + default <SET extends Set<ELEMENT_TYPE>> SET toSet(final SET set) { + giveStream().forEach(set::add); + return set; + } + + /** + * Creates a stream of pairs of the content of the stream and values produced by a supplier. + * + * @param supplier the value supplier. + * @param <ASSOCIATED_TYPE> the type of associated values. + * @return the built stream. + */ + default <ASSOCIATED_TYPE> + ExtendedStream<Pair<ELEMENT_TYPE, ASSOCIATED_TYPE>> associate(final Supplier<ASSOCIATED_TYPE> supplier) { + return Seq.of(giveStream().map(e -> new Pair<ELEMENT_TYPE, + ASSOCIATED_TYPE>(e, supplier.get()))); + } + + /** + * Creates a stream of pairs of the content of the stream and values produces by another stream. + * Once any of the two streams is closed, the produced stream is complete, regardless of potential values remaining + * in the other stream. + * + * @param supplier the value supplier. + * @param <ASSOCIATED_TYPE> the type of associated values. + * @return the built stream. + */ + default <ASSOCIATED_TYPE> + ExtendedStream<Pair<ELEMENT_TYPE, ASSOCIATED_TYPE>> associate(final Stream<ASSOCIATED_TYPE> supplier) { + List<ELEMENT_TYPE> elements = giveStream().toList(); + List<ASSOCIATED_TYPE> assocs = supplier.toList(); + return Seq.of(IntStream.range(0, Math.min(elements.size(), + assocs.size())).mapToObj(i -> new Pair<ELEMENT_TYPE, ASSOCIATED_TYPE>(elements.get(i), assocs.get(i)))); + } + + /** + * Prints the element of the stream on the standard output. + * + * @return this. + */ + default ExtendedStream<ELEMENT_TYPE> print() { + return (ExtendedStream<ELEMENT_TYPE>) giveStream().peek(System.out::println); + } + + /** + * Adds the content of the given stream to the current stream and returns it as a new one. + * + * @param stream the stream to add. + * @return a new stream containing the current one then the given one. + */ + default ExtendedStream<ELEMENT_TYPE> plus(final Stream<ELEMENT_TYPE> stream) { + return Seq.of(Stream.concat(giveStream(), stream)); + } + + /** + * Builds a string by joining the string representation of all contained values, interspersed with the given string + * delimiter. + * + * @param delimiter the delimiter string. + * @return the built {@link String}. + */ + default String join(final String delimiter) { + return giveStream().map(ELEMENT_TYPE::toString).collect(Collectors.joining(delimiter)); + } + + /** + * Builds a string by joining the string representation of all contained values. + * + * @return the built {@link String}. + */ + default String join() { + return giveStream().map(ELEMENT_TYPE::toString).collect(Collectors.joining()); + } + + /** + * Builds a pair of streams by partitioning the current one using the given pivot function. + * + * @param pivot the function to segregate the values of the given stream. + * @param <KEY_TYPE> type of partition key. + * @return the pair of created streams. + */ + default <KEY_TYPE> + ExtendedStream<Pair<KEY_TYPE, ExtendedStream<ELEMENT_TYPE>>> + partition(final Function<ELEMENT_TYPE, KEY_TYPE> pivot) { + Map<KEY_TYPE, List<ELEMENT_TYPE>> map = new HashMap<>(); + giveStream().forEach(e -> { + KEY_TYPE key = pivot.apply(e); + List<ELEMENT_TYPE> assoc = new ArrayList<>(); + if (map.containsKey(key)) { + assoc.addAll(map.get(key)); + } + assoc.add(e); + map.put(key, assoc); + }); + List<Pair<KEY_TYPE, ExtendedStream<ELEMENT_TYPE>>> list = new ArrayList<>(); + for (KEY_TYPE key : map.keySet()) { + list.add(new Pair<>(key, Seq.of(map.get(key).stream()))); + } + return Seq.of(list.stream()); + } + + @Override + public default Iterator<ELEMENT_TYPE> iterator() { + return giveStream().iterator(); + } + + @Override + public default Spliterator<ELEMENT_TYPE> spliterator() { + return giveStream().spliterator(); + } + + @Override + public default boolean isParallel() { + return giveStream().isParallel(); + } + + @Override + public default Stream<ELEMENT_TYPE> sequential() { + return giveStream().sequential(); + } + + @Override + public default Stream<ELEMENT_TYPE> parallel() { + return giveStream().parallel(); + } + + @Override + public default Stream<ELEMENT_TYPE> unordered() { + return giveStream().unordered(); + } + + @Override + public default Stream<ELEMENT_TYPE> onClose(Runnable closeHandler) { + return giveStream().onClose(closeHandler); + } + + @Override + public default void close() { + giveStream().close(); + } +} diff --git a/graphs/java/seq/src/test/java/fr/epita/assistants/seq/ExtendedStreamTest.java b/graphs/java/seq/src/test/java/fr/epita/assistants/seq/ExtendedStreamTest.java new file mode 100644 index 0000000..b0bb911 --- /dev/null +++ b/graphs/java/seq/src/test/java/fr/epita/assistants/seq/ExtendedStreamTest.java @@ -0,0 +1,244 @@ +package fr.epita.assistants.seq; + +import java.lang.reflect.Modifier; +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +import fr.epita.assistants.seq.ExtendedStream.Pair; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class ExtendedStreamTest { + + private static <TYPE> ExtendedStream<TYPE> ctor(final List<TYPE> values) { + // FIXME: replace by your own implementation. + return Seq.of(values); + } + + private static <TYPE> ExtendedStream<TYPE> ctor(final TYPE... values) { + // FIXME: replace by your own implementation. + return Seq.of(values); + } + + private static <TYPE> ExtendedStream<TYPE> ctor(final Stream<TYPE> values) { + // FIXME: replace by your own implementation. + return Seq.of(values); + } + + private static DummyObject dummy(final int id, final String name) { + return new DummyObject(id, name); + } + + @Test + public void isSeqAnInterface() throws ClassNotFoundException { + Class<?> seqClass = Class.forName("fr.epita.assistants.seq.Seq"); + int modifiers = seqClass.getModifiers(); + boolean isInterface = Modifier.isInterface(modifiers); + assertTrue(isInterface, "Seq must be an interface"); + } + + @Test + public void toMapKeyValue() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<DummyObject> es = ctor(dummy(1, "1"), dummy(2, "2"), dummy(2, "4"), dummy(3, "3")); + final Map<Integer, String> map = es.toMap(DummyObject::getId, DummyObject::getName); + assertEquals(3, map.size()); + assertEquals("1", map.get(1)); + assertEquals("4", map.get(2)); + assertEquals("3", map.get(3)); + }); + } + + @Test + public void toMapKeyValueMap() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<DummyObject> es = ctor(dummy(1, "1"), dummy(2, "2"), dummy(2, "4"), dummy(3, "3")); + final Map<Integer, DummyObject> source = new HashMap<>(); + source.put(42, new DummyObject(42, "me")); + final Map<Integer, DummyObject> map = es.toMap(source, DummyObject::getId, it -> it); + assertEquals(4, map.size()); + assertEquals("1", map.get(1).name); + assertEquals("4", map.get(2).name); + assertEquals("3", map.get(3).name); + assertEquals("me", map.get(42).name); + }); + } + + @Test + public void toMapKey() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<DummyObject> es = ctor(dummy(1, "1"), dummy(2, "2"), dummy(2, "4"), dummy(3, "3")); + final Map<Integer, DummyObject> map = es.toMap(DummyObject::getId); + assertEquals(3, map.size()); + assertEquals("1", map.get(1).name); + assertEquals("4", map.get(2).name); + assertEquals("3", map.get(3).name); + }); + } + + + @Test + public void toList() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<DummyObject> es = ctor(dummy(1, "1"), dummy(2, "2"), dummy(2, "4"), dummy(3, "3")); + final List<DummyObject> list = es.toList(); + assertEquals(4, list.size()); + assertEquals("1", list.get(0).name); + assertEquals("2", list.get(1).name); + assertEquals("4", list.get(2).name); + assertEquals("3", list.get(3).name); + + }); + } + + @Test + public void toListWithList() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<DummyObject> es = ctor(dummy(1, "1"), dummy(2, "2"), dummy(2, "4"), dummy(3, "3")); + final List<DummyObject> source = new ArrayList<>(); + source.add(new DummyObject(42, "me")); + final List<DummyObject> list = es.toList(source); + assertEquals(5, list.size()); + assertEquals("me", list.get(0).name); + assertEquals("1", list.get(1).name); + assertEquals("2", list.get(2).name); + assertEquals("4", list.get(3).name); + assertEquals("3", list.get(4).name); + }); + } + + @Test + public void toSet() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<Integer> es = ctor(1, 2, 2, 3); + final Set<Integer> set = es.toSet(); + assertEquals(3, set.size()); + assertTrue(set.contains(1)); + assertTrue(set.contains(2)); + assertTrue(set.contains(3)); + }); + } + + @Test + public void toSetWithSet() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<Integer> es = ctor(1, 2, 2, 3); + final Set<Integer> source = new HashSet<>(); + source.add(1); + source.add(2); + source.add(42); + final Set<Integer> set = es.toSet(source); + assertEquals(4, set.size()); + assertTrue(set.contains(1)); + assertTrue(set.contains(2)); + assertTrue(set.contains(3)); + assertTrue(set.contains(42)); + }); + } + + @Test + public void associateWithSupplier() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<String> es = ctor("a", "b", "c"); + final List<Pair<String, Integer>> list = es.associate(new Increment()).toList(); + + assertEquals(3, list.size()); + assertEquals(new Pair<>("a", 0), list.get(0)); + assertEquals(new Pair<>("b", 1), list.get(1)); + assertEquals(new Pair<>("c", 2), list.get(2)); + + + }); + } + + @Test + public void associateWithStream() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<String> es = ctor("a", "b", "c"); + final List<Pair<String, Integer>> list = es.associate(ctor(0, 1, 2, 3, 4, 5)).toList(); + + assertEquals(3, list.size()); + assertEquals(new Pair<>("a", 0), list.get(0)); + assertEquals(new Pair<>("b", 1), list.get(1)); + assertEquals(new Pair<>("c", 2), list.get(2)); + }); + } + + @Test + public void plus() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<String> es = ctor("a", "b", "c").plus(ctor("d", "e", "f")); + assertEquals("abcdef", es.join()); + }); + } + + @Test + public void join() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<String> es = ctor("a", "b", "c", "d", "e", "f"); + assertEquals("abcdef", es.join()); + }); + } + + @Test + public void joinWithDelimiter() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<String> es = ctor("a", "b", "c", "d", "e", "f"); + assertEquals("a-b-c-d-e-f", es.join("-")); + }); + } + + @Test + public void partition() { + assertTimeoutPreemptively(Duration.ofSeconds(10), () -> { + final ExtendedStream<Integer> es = ctor(0, 1, 2, 3, 4, 5, 6, 7); + final ExtendedStream<Pair<Boolean, ExtendedStream<Integer>>> partitions = es.partition(val -> val % 2 == 0); + final List<Pair<Boolean, ExtendedStream<Integer>>> list = partitions.toList(); + + + assertEquals(list.get(0).first ? "0246" : "1357", list.get(0).second.join()); + assertEquals(list.get(0).first ? "1357" : "0246", list.get(1).second.join()); + }); + } + + static class DummyObject { + public final Integer id; + public final String name; + + public DummyObject(final Integer id, final String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + } + + + static class Increment implements Supplier<Integer> { + private int increment = 0; + + @Override + public Integer get() { + return increment++; + } + } +} |
