All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tailoredshapes.underbar.UnderBar Maven / Gradle / Ivy

There is a newer version: 0.1.2
Show newest version
package com.tailoredshapes.underbar;

import com.tailoredshapes.underbar.data.Fork;
import com.tailoredshapes.underbar.data.Heap;
import com.tailoredshapes.underbar.exceptions.UnderBarred;
import com.tailoredshapes.underbar.function.RegularFunctions;

import java.util.*;
import java.util.function.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static com.tailoredshapes.underbar.Die.*;
import static com.tailoredshapes.underbar.UnderString.commaSep;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toList;

public interface UnderBar {
    Map, Object> lazyCache = Collections.synchronizedMap(hash());

    /**
     * Asserts that a collection contains exactly one value and returns it
     */
    static  T nonce(Iterable ts) {
        Iterator i = ts.iterator();
        dieUnless(i.hasNext(), () -> "input to 'nonce' cannot be empty");
        T result = i.next();
        dieIf(i.hasNext(), () -> "input to 'nonce' has length > 1: " + ts);
        return result;
    }

    /**
     * Asserts that an array contains exactly one value and returns it
     */
    static  T nonce(T[] ts) {
        dieIfNull(ts, () -> "input to 'nonce' cannot be null");
        dieUnless(ts.length == 1, () -> "length of input to 'nonce' must be 1. " + commaSep(list(ts)));
        return ts[0];
    }

    /**
     * Returns true if the collection isEmpty
     */
    static boolean isEmpty(Collection coll) {
        return coll.isEmpty();
    }

    static  Optional maybe(Iterable ts) {
        Iterator i = ts.iterator();
        if (!i.hasNext()) {
            return Optional.empty();
        }
        T result = i.next();
        dieIf(i.hasNext(), () -> "input to 'nonce' has length > 1: " + ts);
        return Optional.of(result);
    }

    /**
     * Executes a runnable if an optional is empty
     */
    static void ifAbsent(Optional maybe, Runnable noT) {
        if (!maybe.isPresent())
            noT.run();
    }

    /**
     * Checks if a value is null. If it isn't execute a function, otherwise execute a supplier
     */
    static  R maybeNull(T maybeNull, Function onT, Supplier noT) {
        return optionally(ofNullable(maybeNull), onT, noT);
    }

    /**
     * Checks if a optional is present. If it isn't execute a function, otherwise execute a supplier
     */
    static  R optionally(Optional maybe, Function onT, Supplier noT) {
        return maybe.isPresent() ? onT.apply(maybe.get()) : noT.get();
    }

    /**
     * Provides a mechanism for getting the value from a hash, or a default value
     */
    static  R maybeGet(Map maybe, K k, Function onT, Supplier noT) {
        return maybeNull(maybe.get(k), onT, noT);
    }

    /**
     * @return An empty ArrayList
     */
    static  List emptyList() {
        return new ArrayList<>();
    }

    /**
     * Returns an fixed size list apply ts in it
     */
    @SafeVarargs
    static  List list(T... ts) {
        return Arrays.asList(ts);
    }


    /**
     * Returns a modifiable list from an iterable
     */
    static  List list(Iterable ts) {
        ArrayList result = new ArrayList<>();
        ts.forEach(result::add);
        return result;
    }

    /**
     * Returns a modifiable list apply ts in it
     */
    @SafeVarargs
    static  List modifiableList(T... ts) {
        List result = new ArrayList<>();
        result.addAll(list(ts));
        return result;
    }

    /**
     * Creates a new HashSet of ts
     */
    @SafeVarargs
    static  Set set(T... ts) {
        return new HashSet<>(Arrays.asList(ts));
    }

    /**
     * Creates a new HashSet of ts from an iterable
     */
    static  Set set(Iterable ts) {
        HashSet result = new HashSet<>();
        ts.forEach(result::add);
        return result;
    }

    /**
     * Creates a new HashSet of T from an iterable of F using a convertion function
     */
    static  Set set(Iterable is, Function toT) {
        return set(map(is, toT));
    }


    /**
     * Lambda require the objects they mutate to be either effectively final or heap allocated.
     * This function heap allocates an object.
     */
    static  Heap heap(T t) {
        return new Heap<>(t);
    }

    /**
     * A convenience function for creating an array
     */
    @SafeVarargs
    static  T[] array(T... ts) {
        return ts;
    }

    /**
     * Returns the first member of an iterable collection
     */
    static  T first(Iterable ts) {
        Iterator iterator = ts.iterator();
        dieUnless(iterator.hasNext(), () -> "can't take first of empty iterable");
        return iterator.next();
    }

    /**
     * Returns the last member of an iterable collection
     */
    static  T last(List ts) {
        dieIf(isEmpty(ts), () -> "can't take last of empty list!");
        return ts.get(ts.size() - 1);
    }

    /**
     * Returns the second member of an iterable.
     */
    static  T second(Iterable ts) {
        Iterator iterator = ts.iterator();
        iterator.next();
        return iterator.next();
    }

    /**
     * Returns everything but the first member of a collection
     */
    static  List rest(List ts) {
        return ts.subList(1, ts.size());
    }

    /**
     * Returns the first n of a collection
     */
    static  List take(int n, List ts) {
        return ts.subList(0, Math.min(n, ts.size()));
    }

    /**
     * Pretty sure this is broken
     */
    static  Optional takeWhile(Iterable ts, Predicate p) {
        for (T next : ts) {
            if (p.test(next)) return optional(next);
        }
        return optional();
    }

    /**
     * Checks for null and size
     */
    static boolean hasContent(Collection coll) {
        return coll != null && coll.size() > 0;
    }


    /**
     * Joins one dimensional collections
     */
    @SafeVarargs
    static  List concat(Collection... collections) {
        ArrayList result = new ArrayList<>(collections[0]);
        for (int i = 1; i < collections.length; i++)
            result.addAll(collections[i]);
        return result;
    }

    /**
     * A union over N sets
     */
    @SafeVarargs
    static  Set union(Set... s) {
        List> sets = list(s);
        return stream(sets).reduce((a, b) -> {
            a.addAll(b);
            return a;
        }).get();

    }

    /**
     * The intersection of N sets
     */
    @SafeVarargs
    static  Set intersection(Set... sets) {
        Set result = new HashSet<>(sets[0]);

        for (int i = 1; i < sets.length; i++) {
            result.retainAll(sets[i]);
        }

        return result;
    }

    /**
     * The difference of N sets
     */
    @SafeVarargs
    static  Set difference(Set... sets) {
        Set result = new HashSet<>(sets[0]);

        for (int i = 1; i < sets.length; i++) {
            result.removeAll(sets[i]);
        }

        return result;
    }

    /**
     * Join a collection of keys and a collection of values into a hash
     */
    static  Map zipmap(Collection keys, Collection values) {
        dieUnless(keys.size() == values.size(), () -> "keys and values must be nonce same size. " + keys.size() + " != " + values.size());
        HashMap result = new HashMap<>();
        Iterator vi = values.iterator();
        keys.forEach(k -> result.put(k, vi.next()));
        return result;
    }

    /**
     * Pairs and lists keys and values from two collections
     */
    static  List> zip(Collection keys, Collection values) {
        dieUnless(keys.size() == values.size(), () -> "keys and values must be nonce same size. " + keys.size() + " != " + values.size());
        List> result = emptyList();
        Iterator vi = values.iterator();
        keys.forEach(k -> result.add(entry(k, vi.next())));
        return result;
    }

    /**
     * Like concat, for maps
     */
    @SafeVarargs
    static  Map merge(Map... ms) {
        List> maps = list(ms);
        Map result = new HashMap<>(first(maps));
        rest(maps).forEach(result::putAll);
        return result;
    }

    /**
     * returns an empty HashMap
     */
    static  Map hash() {
        return new HashMap<>();
    }

    static  Map mapWith(Map m, K k, V v) {
        m.put(k, v);
        return m;
    }

    /**
     * FlatMaps a function over an iterable
     */
    static  List collectAll(Iterable us, Function> toTs) {
        return stream(us).flatMap(u -> stream(toTs.apply(u))).collect(toList());
    }

    /**
     * fells trees into lists
     */
    static > List flatten(Iterable listsOfT) {
        return collectAll(listsOfT, list -> list);
    }


    /**
     * The inverse of filter
     */
    static  List reject(Iterable ts, Predicate predicate) {
        return filter(ts, negate(predicate));
    }

    /**
     * Inverts a predicate
     */
    static  Predicate negate(Predicate pred) {
        return t -> !pred.test(t);
    }

    /**
     * Removes nulls from a collection
     */
    static  List compact(Iterable ts) {
        return filter(ts, t -> t != null);
    }

    /**
     * Removes empty optionals from a collection
     */
    static  List compactOptionals(Iterable> ts) {
        return compact(map(ts, t -> t.orElse(null)));
    }

    /**
     * Convenience function for creating Map.Entry
     */
    static  Map.Entry entry(K key, V value) {
        return new AbstractMap.SimpleEntry<>(key, value);
    }

    /**
     * Returns the number of members of a collection that satisfy a predicate
     */
    static  int count(Iterable ts, Predicate matches) {
        return filter(ts, matches).size();
    }


    /**
     * Takes an array, and a function that can convert members of that array to Map.Entry and builds a hash
     *
     * @throws UnderBarred if there are duplicate keys
     */
    static  Map mapFromEntry(T[] ts, Function> toEntry) {
        return mapFromEntry(list(ts), toEntry);
    }

    /**
     * Takes a list, and a function that can convert members of that array to Map.Entry and builds a hash
     *
     * @throws UnderBarred if there are duplicate keys
     */
    static  Map mapFromEntry(Iterable ts, Function> toEntry) {
        Map result = new LinkedHashMap<>();
        Map> results = new HashMap<>();
        ts.forEach(t -> {
            Map.Entry entry = toEntry.apply(t);
            results.computeIfAbsent(entry.getKey(), k -> emptyList()).add(t);
            result.put(entry.getKey(), entry.getValue());
        });
        List duplicateKeys = map(filter(results.entrySet(), entry -> entry.getValue().size() > 1), Map.Entry::getKey);
        dieUnless(duplicateKeys.isEmpty(), () -> "Duplicates: " + filterKeys(results, duplicateKeys::contains));
        return result;
    }

    /**
     * Creates a new hash by Iterating over a hash, using toU to modify the values
     */
    static  Map modifyValues(Map m, Function toU) {
        return m.entrySet().stream().map(entry -> entry(
                entry.getKey(),
                rethrow(
                        () -> toU.apply(entry.getValue()),
                        () -> {
                            V value = entry.getValue();
                            return "failed to produce new value for key '" + entry.getKey() + "' and value '" + value + "'";
                        }
                )
        )).collect(HashMap::new, (m1, entry) -> m1.put(entry.getKey(), entry.getValue()), HashMap::putAll);
    }

    /**
     * Creates a new hash by Iterating over a hash, using toU to modify the keys
     */
    static  Map modifyKeys(Map m, Function toU) {
        return m.entrySet().stream().map(entry -> entry(toU.apply(entry.getKey()), entry.getValue()))
                .collect(HashMap::new, (m1, entry) -> m1.put(entry.getKey(), entry.getValue()), HashMap::putAll);
    }

    /**
     * Create a new hash apply only the members of m that satisfy the predicate
     */
    static  Map filterKeys(Map m, Predicate predicate) {
        return m.entrySet().stream()
                .filter(entry -> predicate.test(entry.getKey()))
                .collect(HashMap::new, (m1, entry) -> m1.put(entry.getKey(), entry.getValue()), HashMap::putAll);
    }


    static  Map> groupBy(Iterable vs, Function toK) {
        return tap(hash(), result -> vs.forEach(v ->
                result.computeIfAbsent(toK.apply(v), k -> emptyList()).add(v)));
    }

    /**
     * Find position of first element that statisfies the predicate
     */
    static  Optional indexOf(Iterable ts, Predicate isItem) {
        long i = 0L;

        for (T t : ts) {
            if (isItem.test(t))
                return optional(i);
            i++;
        }
        return optional();
    }

    /**
     * Split a collection into a fork based on a predicate
     * 

* A function is used to maintain compatibility apply groupby */ static Fork tee(Iterable ts, Function isIn) { Map> result = groupBy(ts, isIn); return new Fork<>(result.getOrDefault(true, list()), result.getOrDefault(false, list())); } /** * Iterable to stream */ static Stream stream(Iterable in) { return StreamSupport.stream(in.spliterator(), false); } /** * Map a function over an iterable */ static List map(Iterable fs, Function toT) { return stream(fs).map(toT).collect(toList()); } /** * Map a function over an iterble apply an zero based index */ static List mapWithIndex(Iterable fs, BiFunction toT) { Heap index = heap(0L); return stream(fs).map(f -> toT.apply(f, index.value++)).collect(toList()); } /** * Map a function over an array */ static List map(F[] fs, Function toT) { return map(Arrays.asList(fs), toT); } /** * Map a function over a hash */ static List map(Map m, BiFunction tOfKV) { return map(m.entrySet(), entry -> tOfKV.apply(entry.getKey(), entry.getValue())); } /** * Return a new list containing only the members that satisfy the predicate */ static List filter(Iterable ts, Predicate predicate) { return stream(ts).filter(predicate).collect(toList()); } /** * Loops over a hash applying onKV, but returns void */ static void each(Map m, BiConsumer onKV) { m.entrySet().forEach(entry -> onKV.accept(entry.getKey(), entry.getValue())); } /** * Repeats the consumer N times apply an zero based index */ static void doTimes(int n, Consumer onN) { for (int i = 0; i < n; i++) onN.accept(i); } /** * Repeats the runnable n times */ static void doTimes(int n, Runnable r) { for (int i = 0; i < n; i++) r.run(); } /** * returns the result of applying the function apply an index */ static List makeTimes(int n, Function r) { return tap(emptyList(), result -> { for (int i = 0; i < n; i++) { result.add(r.apply(i)); } }); } /** * Returns the result of applyin the supplier n times without an index */ static List makeTimes(int n, Supplier r) { return tap(emptyList(), result -> { for (int i = 0; i < n; i++) result.add(r.get()); }); } /** * Boilerplate methods for generating a hash hash. */ static Map hash(K k1, V v1) { return mapWith(hash(), k1, v1); } static Map hash(K k1, V v1, K k2, V v2) { return mapWith(hash(k1, v1), k2, v2); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3) { return mapWith(hash(k1, v1, k2, v2), k3, v3); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { return mapWith(hash(k1, v1, k2, v2, k3, v3), k4, v4); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { return mapWith(hash(k1, v1, k2, v2, k3, v3, k4, v4), k5, v5); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) { return mapWith(hash(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5), k6, v6); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) { return mapWith(hash(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6), k7, v7); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) { return mapWith(hash(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7), k8, v8); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) { return mapWith(hash(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8), k9, v9); } static Map hash(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) { return mapWith(hash(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9), k10, v10); } /** * Returns true if any of the members of the iterable satisfy the predicate */ static boolean any(Iterable ts, Predicate pred) { return hasContent(filter(ts, pred)); } /** * Returns true if all of the memebers of an interable satisfy the predicate */ static boolean all(Iterable ts, Predicate pred) { return !hasContent(reject(ts, pred)); } /** * Return a list of n t */ static List repeat(T t, int n) { return IntStream.range(0, n).mapToObj(i -> t).collect(toList()); } static List sort(Iterable ts) { return stream(ts).sorted().collect(toList()); } /** * Returns a list sorted by toU */ static > List sortBy(Iterable ts, Function toU) { return stream(ts).sorted((t1, t2) -> toU.apply(t1).compareTo(toU.apply(t2))).collect(toList()); } /** * Returns a SortedMaps sorted by the natural order of keys */ static SortedMap sort(Map m) { return new TreeMap<>(m); } /** * Returns a SortedMap sored by toU */ static > SortedMap sortBy(Map m, Function toU) { TreeMap result = new TreeMap<>((t1, t2) -> toU.apply(t1).compareTo(toU.apply(t2))); result.putAll(m); return result; } /** * Applys a T to a function apply side effects */ static void withVoid(T t, Consumer onT) { onT.accept(t); } static void withVoid(T t, U u, BiConsumer onTandU) { onTandU.accept(t, u); } static void withVoid(T t, U u, V v, RegularFunctions.TriConsumer f) { f.accept(t, u, v); } static void withVoid(T t, U u, V v, W w, RegularFunctions.QuadConsumer f) { f.accept(t, u, v, w); } static void withVoid(T t, U u, V v, W w, X x, RegularFunctions.PentaConsumer f) { f.accept(t, u, v, w, x); } static void withVoid(T t, U u, V v, W w, X x, Y y, RegularFunctions.HexConsumer f) { f.accept(t, u, v, w, x, y); } static void withVoid(T t, U u, V v, W w, X x, Y y, Z z, RegularFunctions.SeptaConsumer f) { f.accept(t, u, v, w, x, y, z); } static void withVoid(T t, U u, V v, W w, X x, Y y, Z z, A a, RegularFunctions.OctaConsumer f) { f.accept(t, u, v, w, x, y, z, a); } /** * Returns the value of applying a function */ static R apply(T t, Function onT) { return onT.apply(t); } static R apply(T t, U u, BiFunction onT) { return onT.apply(t, u); } static R apply(T t, U u, V v, RegularFunctions.TriFunction onT) { return onT.apply(t, u, v); } static R apply(T t, U u, V v, W w, RegularFunctions.QuadFunction onT) { return onT.apply(t, u, v, w); } static R apply(T t, U u, V v, W w, X x, RegularFunctions.PentaFunction onT) { return onT.apply(t, u, v, w, x); } static R apply(T t, U u, V v, W w, X x, Y y, RegularFunctions.HexFunction onT) { return onT.apply(t, u, v, w, x, y); } static R apply(T t, U u, V v, W w, X x, Y y, Z z, RegularFunctions.SeptaFunction onT) { return onT.apply(t, u, v, w, x, y, z); } static R apply(T t, U u, V v, W w, X x, Y y, Z z, A a, RegularFunctions.OctaFunction onT) { return onT.apply(t, u, v, w, x, y, z, a); } /** * Apply t to onT and return t */ static T tap(T t, Consumer onT) { onT.accept(t); return t; } /** * Only evaluates makeT when necessary */ static Supplier lazy(Supplier makeT) { return () -> (T) lazyCache.computeIfAbsent(makeT, Supplier::get); } static void clearLazyCache() { lazyCache.clear(); } /** * Create an optional with value t */ static Optional optional(T t) { if(t instanceof Optional) { return (Optional) t; } return Optional.of(t); } /** * Create an empty optional */ static Optional optional() { return Optional.empty(); } /** * Creates a new list with the contents shuffled */ static List shuffle(List ts) { List nl = new ArrayList<>(ts); Collections.shuffle(nl); return nl; } /** * Split ts into smaller lists of size */ static List> partition(List ts, int size) { List> result = emptyList(); int i = 0; while (i * size < ts.size()) { result.add(ts.subList(i * size, Math.min((i + 1) * size, ts.size()))); i++; } return result; } /** * Allows comparison of doubles */ static boolean almostEqual(Double lvalue, Double rvalue) { return Math.abs(lvalue - rvalue) < 0.000001; } /** * Allows comparision of doubles against numbers */ static boolean almostEqual(Double lvalue, Number rvalue) { return almostEqual(lvalue, rvalue.doubleValue()); } /** * Creates a list of 0 -> max */ static List range(int max) { return makeTimes(max, i -> i); } /** * Creates a list of start -> end */ static List range(int start, int end) { return makeTimes(end - start, i -> i + start); } static R reduce(Collection col, R identity, BiFunction fn) { Heap h = heap(identity); for (T t : col) { h.value = fn.apply(h.value, t); } return h.value; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy