Skip to content

Amazing Ruby's "Enumerable" ported to Java

License

Notifications You must be signed in to change notification settings

dykov/enumerable4j

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maven Javadocs License: MIT Commit activity Hits-of-Code

CI 0pdd Dependency Status Known Vulnerabilities

DevOps By Rultor.com EO badge We recommend IntelliJ IDEA

Qulice Maintainability Rating Codebeat Badge Codacy Badge Codecov

Overview

enumerable4j is a Ruby's well known Enumerable ported to java as interface with set of default methods which simplify typical operations with collections.

/**
 * The iterable with primitive operations witch simplify typical actions like count, map, etc.
 *
 * The API is based on Ruby's Enumerable:
 *  https://ruby-doc.org/core-2.6/Enumerable.html.
 *
 * The Enumerable provides methods with several traversal and searching features, and with the
 * ability to sort. The class must provide a method each, which yields successive members of the
 * collection.
 *
 * @param <T> The type of entities.
 * @since 0.1.0
 */
public interface Enumerable<T> extends Collection<T> {
    /**
     * Passes each element of the collection to the each given function.
     * The given null predicates are skipped.
     * If no predicate (null) is given, then false is returned instead.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return True if the functions never return false.
     */
    default boolean all(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Passes at least one element of the collection to the each given function.
     * The given null predicates are skipped.
     * If no predicate (null) is given, then false is returned instead.
     * @param first The function to match at least one element.
     * @param other The array of functions to match at least one element.
     * @return True if functions never return true at least once.
     */
    default boolean any(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Doesn't passes elements of the collection to the each given function.
     * The given null predicates are skipped.
     * If no predicate (null) is given, then true is returned instead.
     * @param first The function to match none elements.
     * @param other The array of functions to match none elements.
     * @return True if the functions never returns false or nil.
     */
    default boolean none(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns an enumerable containing all elements of enumerable for which the given functions
     *  return a true value.
     * The given null predicates are skipped.
     * If no predicate (null) is given, then an empty enumerable is returned instead.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return The enumerable.
     */
    default Enumerable<T> select(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns an enumerable containing all elements of enumerable for which the given function
     *  returns a false value.
     * The given null predicates are skipped.
     * If no predicate (null) is given, then 'this' is returned instead.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return The enumerable.
     */
    default Enumerable<T> reject(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns an enumerable containing first element of enumerable for which the given function
     *  returns a true value.
     * The given null predicates are skipped.
     * If no predicate (null) is given, or no element found then null is returned instead.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return The first element of enumerable, that matches predicate.
     */
    default T find(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns an enumerable containing first element of enumerable for which the given function
     *  returns a true value.
     * The given null predicates are skipped.
     * If no predicate (null) is given, or no element found then alternative is returned instead.
     * @param alt The alternative to return in case of null predicate or no element found.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return The first element of enumerable, that matches predicate.
     */
    default T find(X alt, Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns an enumerable containing all elements, on which given function was applied.
     * If no function (null) is given, then 'this' is returned instead.
     * @param fnc The function to apply to each element.
     * @param <R> The type of target entity.
     * @return The enumerable.
     */
    default <R> Enumerable<R> map(Function<? super T, ? extends R> fnc) {
        // ...
    }

    /**
     * Returns the number of elements that are present in enumerable for which the given
     * function return true.
     * The given null predicates are skipped.
     * If no function (null) is given, then 0 is returned instead.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return Number of elements satisfying the given function.
     */
    default long count(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns a result of the reduction of the elements in this stream,
     * using provided identity value and accumulation function operator.
     * If no function (null) is given, then identity is returned instead.
     * @param idn The identity value of the accumulation function.
     * @param opr The accumulation function operator which combining previous and current values.
     * @return Result of of combining elements.
     */
    default T reduce(T idn, BinaryOperator<T> opr) {
        // ...
    }

    /**
     * Returns an enumerable containing all elements of enumerable
     *  after the first one which corresponds the condition.
     * If no predicate (null) is given, then empty enumerable is returned instead.
     * @param prd The function to match element after which enumerable elements should be returned.
     * @return The enumerable.
     */
    default Enumerable<T> after(Predicate<T> prd) {
        // ...
    }

    /**
     * Returns an enumerable containing a certain number of elements of enumerable
     *  after the first one which corresponds the condition.
     * If no predicate (null) is given, then empty enumerable is returned instead.
     * @param prd The function to match element after which enumerable elements should be returned.
     * @param size The number of elements the enumerable should be limited to.
     * @return The enumerable.
     * @throws IllegalArgumentException If the size is negative.
     */
    default Enumerable<T> after(Predicate<T> prd, long size) {
        // ...
    }

    /**
     * Returns the next element of enumerable after the first one which corresponds the condition.
     * If no predicate (null) is given, or no element found then null is returned instead.
     * @param prd The function to match element after which enumerable element should be returned.
     * @return The next element of enumerable after the first one which corresponds the condition.
     */
    default T next(Predicate<T> prd) {
        // ...
    }

    /**
     * Returns the next element of enumerable after the first one which corresponds the condition.
     * If no predicate (null) is given, or no element found then alternative is returned instead.
     * @param prd The function to match element after which enumerable element should be returned.
     * @param alt The alternative to return in case of null predicate or no element found.
     * @return The next element of enumerable after the first one which corresponds the condition.
     */
    default T next(Predicate<T> prd, T alt) {
        // ...
    }

    /**
     * Returns a new enumerable which contains the items of the original collection
     *  and the added items of the given enumerable.
     * If no enumerable (null) is given, then 'this' is returned instead.
     * @param enm The given enumerable.
     * @return The enumerable.
     */
    default Enumerable<T> chain(Enumerable<T> enm) {
        // ...
    }

    /**
     * Returns an enumerable consisting of the elements of the collection,
     *  additionally performing the provided action on each element of the enumerable.
     * @param act An action to perform on the elements.
     * @return The enumerable.
     */
    default Enumerable<T> each(Consumer<T> act) {
        // ...
    }
    
    /**
     * Returns an enumerable containing first elements of specified size from the enumerable.
     * @param num The number of elements the enumerable should be limited to.
     * @return The enumerable.
     * @throws IllegalArgumentException If the size is negative.
     */
    default Enumerable<T> take(long num) {
        // ...
    }

    /**
     * Drops first elements of specified size,
     *  and returns an enumerable containing the rest of the elements.
     * @param num The number of elements to be dropped.
     * @return The enumerable.
     * @throws IllegalArgumentException If the size is negative.
     */
    default Enumerable<T> drop(long num) {
        // ...
    }

    /**
     * The method returns true if the functions return true exactly once.
     * The given null predicates are skipped.
     * If no predicate (null) is given, then false is returned instead.
     * @param first The function to match each element.
     * @param other The array of functions to match each element.
     * @return True if the functions returns true exactly once.
     */
    default boolean one(Predicate<T> first, Predicate<T>... other) {
        // ...
    }

    /**
     * Returns a new enumerable containing the unique elements.
     * It compares values using the {@link #hashCode} and {@link #equals} methods for efficiency.
     * @return The enumerable.
     */
    default Enumerable<T> uniq() {
        // ...
    }

    /**
     * Returns a new enumerable containing the unique elements which corresponds the condition
     *  of the given function.
     * If no function (null) is given, then empty enumerable is returned instead.
     * @param fnc The function to apply to each element.
     * @param <R> The type of function result entity.
     * @return The enumerable.
     */
    default <R> Enumerable<T> uniq(Function<? super T, ? extends R> fnc) {
        // ...
    }
}

See more.

How to use

  1. Get the latest version here:

    <dependency>
      <groupId>io.github.dgroup</groupId>
      <artifactId>enumerable4j</artifactId>
      <version>${version}</version>
    </dependency>
  2. Assign the Enumerable interface with default methods to your own collection

    /**
     * The collection which you implemented in your project for some purposes.
     */
    public class YourOwnCollection<T> extends Collection<T> implements Enumerable<T> {
        //
    }

    You may (but not required) override the default implementations of methods from Enumerable if needed.

  3. Java version required: 1.8+.

  4. Comparing matrix with other libs:

    enumerable4j (MIT) Java 8 cactoos (MIT) eclipse-collections (EDL)
    .all(...) .stream().allMatch(...) new And<>(...,...).value() tbd
    .any(...) .stream().anyMatch(...) new Or<>(...,...).value() tbd
    .none(...) .stream().noneMatch(...) new And<>(...,...).value() tbd
    .select(...) .stream().filter(...).collect(Collectors.toList()) new Filtered<>(...,...) tbd
    .reject(...) .stream().filter((...).negate()).collect(Collectors.toList()) new Filtered<>(...,...) tbd
    .map(...) .stream().map(...).collect(Collectors.toList()) new Mapped<>(...,...) tbd
    .count(...) .stream().filter(...).count() new Filtered<>(...).size() tbd
    .find(...) .stream().filter(...).findFirst().orElse(...) new FirstOf<>(...,...).value() tbd
    .reduce(...,...) .stream().reduce(...,...) new Reduced<>(...,...).value() tbd
    .after(...) tbd
    .next(...) tbd
    .chain(...) tbd
    .each(...) .stream().forEach(...) new ForEach<>(...).exec(...) tbd
    .take(...) .stream().limit(...).collect(Collectors.toList()) new Sliced<>(0,...,...) tbd
    .drop(...) .stream().skip(...).collect(Collectors.toList()) new Sliced<>(...,...,...) tbd
    .one(...) .stream().filter(...).count() == 1 new Filtered<>(...).size() == 1 tbd
    .uniq(...) .stream().skip(...).collect(Collectors.toSet()) tbd

.all

YourOwnCollection<Integer> src = ...           // with elements [1, 2, 3]   
boolean allPositive = src.all(val -> val > 0); // true 

.any

YourOwnCollection<Integer> src = ...             // with elements [-1, 0, 1]
boolean oneIsPositive = src.any(val -> val > 0); // true 

.none

YourOwnCollection<Integer> src = ...               // with elements [-2, -1, 0]
boolean noneIsPositive = src.none(val -> val > 0); // true 

.select

YourOwnCollection<Integer> src = ...                       // with elements [-1, 1, 2]
Enumerable<Integer> positive = src.select(val -> val > 0); // [1, 2] 

.reject

YourOwnCollection<Integer> src = ...                       // with elements [-1, 1, 2]
Enumerable<Integer> negative = src.reject(val -> val > 0); // [-1]

.map

YourOwnCollection<Integer> src = ...                    // with elements [0, 1, 2]
Enumerable<Integer> positive = src.map(val -> val + 1); // [1, 2, 3] 

.count

YourOwnCollection<Integer> src = ...            // with elements [-1, 0, 1]
long countNegative = src.count(val -> val < 0); // 1

.find

YourOwnCollection<Integer> src = ...                // with elements [-1, 0, 1]
Integer first = src.find(val -> val > 0);           // 1 
Integer alternative = src.find(50, val -> val > 5); // 50                

.reduce

YourOwnCollection<Integer> src = ...       // with elements [1, 2, 3]   
Integer sum = src.reduce(0, Integer::sum); // 6 

.after

YourOwnCollection<Integer> src = ...                                    // with elements [2, 3, 4, 5, 6]
Enumerable<Integer> afterThree = src.after(val -> val == 3);            // [4, 5, 6] 
Enumerable<Integer> firstTwoAfterThree = src.after(val -> val == 3, 2); // [4, 5]                

.next

YourOwnCollection<Integer> src = ...                // with elements [1, 2, 3, 4]
Integer next = src.next(val -> val == 2);           // 3
Integer alternative = src.next(val -> val > 5, -1); // -1                

.chain

YourOwnCollection<Integer> src = ...                                               // with elements [1, 2]
Enumerable<Integer> joined = src.chain(new Linked<>(3)).chain(new Linked<>(4, 5)); // [1, 2, 3, 4, 5] 

.each

YourOwnCollection<Integer> src = ...                   // with elements [1, 2, 3]
Enumerable<Integer> buf = src.each(System.out::print); // [1, 2, 3] , printed: "123"

.take

YourOwnCollection<Integer> src = ...     // with elements [1, 2, 3]
Enumerable<Integer> taken = src.take(2); // [1, 2]

.drop

YourOwnCollection<Integer> src = ...     // with elements [1, 2, 3]
Enumerable<Integer> taken = src.drop(2); // [3]

.one

YourOwnCollection<Integer> src = ...           // with elements [-1, 0, 1]
boolean onePositive = src.one(val -> val > 0); // true

.uniq

YourOwnCollection<Linked<Integer>> src = ...                             // with elements [[1, 2], [3, 4], [1, 2], [3, 4, 5]]
Enumerable<Linked<Integer>> unique = src.uniq();                       // [[1, 2], [3, 4], [3, 4, 5]]
Enumerable<Linked<Integer>> uniqueByKey = src.uniq(enm -> enm.get(0)); // [[1, 2], [3, 4]]

How to contribute?

EO badge

  1. Pull requests are welcome! Don't forget to add your name to contribution section and run this, beforehand:
    mvn -Pqulice clean install
  2. Everyone interacting in this project’s codebases, issue trackers, chat rooms is expected to follow the code of conduct.
  3. Latest maven coordinates here:
    <dependency>
        <groupId>io.github.dgroup</groupId>
        <artifactId>enumerable4j</artifactId>
        <version>${version}</version>
    </dependency>

Contributors

About

Amazing Ruby's "Enumerable" ported to Java

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 98.5%
  • Shell 1.5%