me.shaftesbury.utils.functional.Functional Maven / Gradle / Ivy
package me.shaftesbury.utils.functional;
import org.javatuples.Pair;
import org.javatuples.Triplet;
import java.util.*;
/**
* Herein are contained some standard algorithms from functional programming.
* See Functional Programming
* for more information
*/
public final class Functional
{
private Functional() {}
/**
* A simple predicate which checks the contents of the string parameter.
* @param s the input string
* @return true if s is either null or s is the empty string; false otherwise.
*/
public final static boolean isNullOrEmpty(final String s)
{
return s==null || s.isEmpty();
}
/**
* Concatenate all of the input elements into a single string where each element is separated from the next by the supplied delimiter
* @param delimiter used to separate consecutive elements in the output
* @param strs input sequence, each element of which must be convertible to a string
* @param the type of the element in the input sequence
* @return a string containing the string representation of each input element separated by the supplied delimiter
*/
public final static String join(final String delimiter, final Iterable strs)
{
if(strs==null) return "";
final Iterator it = strs.iterator();
final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
while(it.hasNext())
{
if(!isFirst) sb.append(delimiter);
sb.append(it.next());
isFirst=false;
}
return sb.toString();
}
/**
* A string function: generate a string that contains the 'unitOfIndentation' repeated 'howMany' times prepended to 'indentThis'
* @param howMany times should the unitOfIndentation be prefixed to the supplied 'indentThis' string
* @param unitOfIndentation the indentation
* @param indentThis the input string that should be indented
* @return a string indenting the input string by the indicated number of units
*/
public final static String indentBy(final int howMany, final String unitOfIndentation, final String indentThis)
{
final Collection indentation = init(
new Func() {
@Override
public String apply(final Integer integer) {
return unitOfIndentation;
}
}, howMany);
return fold(new Func2() {
@Override
public String apply(final String state, final String str) {
return str + state;
}
}, indentThis, indentation);
}
/**
* foldAndChoose: fold except that instead of folding every element in the input sequence, fold
* only those for which the fold function 'f' returns a Some value (see Option)
* @param f is the fold function modified such that the return value contains an Option in addition to the state
* @param initialValue the seed for the fold function
* @param input the input sequence
* @param the type of the initialValue / seed
* @param the type of the element in the input sequence
* @return the folded value paired with those transformed elements which are Some
* @throws OptionNoValueAccessException
*/
public final static Pair> foldAndChoose(
final Func2>> f,
final A initialValue, final Iterable input) throws OptionNoValueAccessException
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
A state = initialValue;
final List results = new ArrayList();
for (final B b : input)
{
final Pair> intermediate = f.apply(state, b);
state = intermediate.getValue0();
if (!intermediate.getValue1().isNone())
results.add(intermediate.getValue1().Some());
}
return new Pair>(state, Collections.unmodifiableList(results));
}
public static final List toList(final Enumeration input)
{
final List output = new ArrayList();
while(input.hasMoreElements())
output.add(input.nextElement());
return Collections.unmodifiableList(output);
}
/**
* Analogue of string.Join for List with the addition of a user-defined map function
*
* @param the type of the element in the input sequence
* @param separator inserted between each transformed element
* @param l the input sequence
* @param fn map function (see map) which is used to transform the input sequence
* @return a string containing the transformed string value of each input element separated by the supplied separator
*/
public final static String join(final String separator, final Iterable l, final Func super T, String> fn)
{
if (l == null) throw new IllegalArgumentException("l");
if (fn == null) throw new IllegalArgumentException("fn");
return join(separator, map(fn,l));
}
/**
* @param lowerBound
* @param upperBound
* @param val
* @param the type of the input element
* @return lowerBound < val < upperBound
*/
public final static >boolean between(final T lowerBound, final T upperBound, final T val)
{
if (val == null) throw new IllegalArgumentException("val");
return val.compareTo(lowerBound) == 1 && val.compareTo(upperBound) == -1;
}
/**
* Find the first element from the input sequence for which the supplied predicate returns true
* find: (A -> bool) -> A list -> A
* @param f predicate
* @param input sequence
* @param the type of the element in the input sequence
* @throws java.lang.IllegalArgumentException if f or input are null
* @throws java.util.NoSuchElementException if no element is found that satisfies the predicate
* @return the first element from the input sequence for which the supplied predicate returns true
*/
public final static A find(final Func super A,Boolean> f, final Iterable input)
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
for(final A a : input)
if(f.apply((a)))
return a;
throw new NoSuchElementException();
}
/**
* Curried find.
* Find the first element from the input sequence for which the supplied predicate returns true
* find: (A -> bool) -> A list -> A
* @param f predicate
* @param the type of the element in the input sequence
* @throws java.lang.IllegalArgumentException if f or input are null
* @throws java.util.NoSuchElementException if no element is found that satisfies the predicate
* @return a curried function that expects an input sequence which it feeds to the predicate f
* which returns the first element from the input sequence for which the supplied predicate returns true
* @see Currying
*/
public final static Func,A> find(final Func super A,Boolean> f)
{
return new Func, A>() {
@Override
public A apply(final Iterable input) {
return Functional.find(f,input);
}
};
}
/**
* As find except that here we return the zero-based position in the input sequence of the found element
* findIndex: (A -> bool) -> A list -> int
* @param f predicate
* @param input sequence
* @param the type of the element in the input sequence
* @throws java.lang.IllegalArgumentException if f or input are null
* @throws java.util.NoSuchElementException if no element is found that satisfies the predicate
* @return the position in the input sequence of the first element from the input sequence for which the supplied predicate
* returns true
*/
public static int findIndex(final Func f, final Iterable extends A> input)
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
int pos = 0;
for (final A a : input)
if (f.apply(a))
return pos;
else pos++;
throw new IllegalArgumentException();
}
/**
* As find except that here we return the last element in the input sequence that satisfies the predicate 'f'
* findLast: (A -> bool) -> A seq -> A
* @param f predicate
* @param input sequence
* @param the type of the element in the input sequence
* @throws java.lang.IllegalArgumentException if f or input are null
* @throws java.util.NoSuchElementException if no element is found that satisfies the predicate
* @return the last element in the input sequence for which the supplied predicate returns true
*/
public final static A findLast(final Func super A,Boolean> f, final Iterable input)
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
final Pair,Iterable> p = takeNAndYield(input,1);
final Pair seed = Pair.with(p.getValue0().get(0),f.apply(p.getValue0().get(0)));
final Pair result = fold(new Func2,A,Pair>(){
@Override public Pair apply(final Pair state, final A item){return f.apply(item)?Pair.with(item,true):state;}
},seed,p.getValue1());
if(result.getValue1()) return result.getValue0();
throw new NoSuchElementException();
}
/**
* As find except that here we return the last element in the input sequence that satisfies the predicate 'f'
* findLast: (A -> bool) -> A list -> A
* @param f predicate
* @param input sequence
* @param the type of the element in the input sequence
* @throws java.lang.IllegalArgumentException if f or input are null
* @throws java.util.NoSuchElementException if no element is found that satisfies the predicate
* @return the last element in the input sequence for which the supplied predicate returns true
*/
public final static A findLast(final Func super A,Boolean> f, final List input)
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
for (final A a : Iterators.reverse(input))
if (f.apply(a))
return a;
throw new NoSuchElementException();
}
/**
* A curried version of findLast.
* As find except that here we return the last element in the input sequence that satisfies the predicate 'f'
* findLast: (A -> bool) -> A list -> A
* @param f predicate
* @param the type of the element in the input sequence
* @throws java.lang.IllegalArgumentException if f or input are null
* @throws java.util.NoSuchElementException if no element is found that satisfies the predicate
* @return the last element in the input sequence for which the supplied predicate returns true
* @see Currying
*/
public final static Func,A> findLast(final Func f)
{
return new Func, A>() {
@Override
public A apply(final List input) {
return Functional.findLast(f,input);
}
};
}
/**
* 'pick' is an analogue of find. Instead of a predicate, 'pick' is passed a map function which returns an Option.
* Each element of the input sequence is supplied in turn to the map function 'f' and the first non-None Option to be returned from
* the map function is returned by 'pick' to the calling code.
* pick: (A -> B option) -> A seq -> B
*
* @param f the map function.
* @param input the input sequence
* @param the type of the element in the input sequence
* @param the type of the output element
* @return the first non-None transformed element of the input sequence
*/
public static B pick(final Func> f, final Iterable extends A> input)
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
for(final A a : input)
{
final Option intermediate = f.apply(a); // which is, effectively, if(f(a)) return f(a), but without evaluating f twice
if (!intermediate.isNone())
return intermediate.Some();
}
throw new NoSuchElementException();
}
/**
* 'pick' is an analogue of find. Instead of a predicate, 'pick' is passed a map function which returns an Option.
* Each element of the input sequence is supplied in turn to the map function 'f' and the first non-None Option to be returned from
* the map function is returned by 'pick' to the calling code.
*
* This is a curried implementation of 'pick'
*
* pick: (A -> B option) -> A seq -> B
*
* @param f the map function.
* @param the type of the element in the input sequence
* @param the type of the output element
* @return the first non-None transformed element of the input sequence
* @see Currying
*/
public static Func,B> pick(final Func super A,Option> f)
{
return new Func, B>() {
@Override
public B apply(final Iterable input) {
return Functional.pick(f,input);
}
};
}
/**
* In, used for functional composition. This is the simple reversal function. y(x) is equivalent to x.In(y)
* See Function Composition
* @param input the object which we wish to pass to the function parameter
* @param f the function we wish to evaluate
* @param the base type of the input element. That is AA extends A
* @param the type of the output of the function f
* @param the type of the input
* @return f(input)
*/
public final static B in(final AA input, final Func f)
{
return f.apply(input);
}
/**
* Then, the functional composition operator. Execute the first function then execute the second, passing the results
* of the first as the input to the second.
* See Function Composition
* @param f the first function to execute.
* @param g the second function to execute. The input to this function will be the result of the first function, f
* @param the type of the input to f
* @param the type of the input to g and a base class of the output of f
* @param the type of the output of g
* @return a function equivalent to g(f(x))
*/
public final static Func then(final Func f, final Func g)
{
return new Func()
{
@Override
public C apply(final A x)
{
return g.apply(f.apply(x));
}
};
}
/**
* The identity transformation function: that is, the datum supplied as input is returned as output
* @param the type of the input element
* @return a function which is the identity transformation
*/
public final static Func identity()
{
return new Func() {
@Override
public T apply(final T t) {
return t;
}
};
}
/**
* isEven a function that accepts an integer and returns a boolean that indicates whether the passed integer
* is or is not an even integer
*/
public static final Func isEven = new Func()
{
@Override
public Boolean apply(final Integer i)
{
return i % 2 == 0;
}
};
/**
* isOdd a function that accepts an integer and returns a boolean that indicates whether the passed integer
* is or is not an odd integer
*/
public static final Func isOdd = new Func()
{
@Override
public Boolean apply(final Integer i)
{
return i % 2 != 0;
}
};
/**
* count a function that accepts a counter and another integer and returns 1 + counter
*/
public static final Func2 count = new Func2() {
@Override
public Integer apply(final Integer state, final Integer b) {
return state + 1;
}
};
/**
* sum a function that accepts two integers and returns the sum of them
*/
public static final Func2 sum = new Func2() {
@Override
public Integer apply(final Integer state, final Integer b) {
return state + b;
}
};
/**
* @param the type of that, the input argument
* @return a function that compares its supplied argument with the 'that' argument and returns true if 'this' is greater than
* 'that' or false otherwise
*/
public static final >Func greaterThan(final T that)
{
return new Func()
{
@Override
public Boolean apply(final T ths)
{
return ths.compareTo(that)>0;
}
};
}
/**
* @param the type of that, the input argument
* @return a function that compares its supplied argument with the 'that' argument and returns true if 'this' is greater than
* or equal to 'that' or false otherwise
*/
public static final >Func greaterThanOrEqual(final T that)
{
return new Func()
{
@Override
public Boolean apply(final T ths)
{
return ths.compareTo(that)>=0;
}
};
}
/**
* @param the type of that, the input argument
* @return a function that compares its supplied argument with the 'that' argument and returns true if 'this' is less than
* 'that' or false otherwise
*/
public static final >Func lessThan(final T that)
{
return new Func()
{
@Override
public Boolean apply(final T ths)
{
return ths.compareTo(that)<0;
}
};
}
/**
* @param the type of that, the input argument
* @return a function that compares its supplied argument with the 'that' argument and returns true if 'this' is less than
* or equal to 'that' or false otherwise
*/
public static final >Func lessThanOrEqual(final T that)
{
return new Func()
{
@Override
public Boolean apply(final T ths)
{
return ths.compareTo(that)<=0;
}
};
}
/**
* The init function, not dissimilar to list comprehensions, which is used to return a new finite list whose contents are
* determined by successive calls to the function f.
* init: (int -> A) -> int -> A list
* @param f generator function used to produce the individual elements of the output list. This function is called by init
* with the unity-based position of the current element in the output list being produced. Therefore, the first time
* f is called it will receive a literal '1' as its argument; the second time '2'; etc.
* @param howMany the number of elements in the output list
* @param the type of the element in the output sequence
* @return a list of 'howMany' elements of type 'T' which were generated by the function 'f'
*/
public final static List init(final Func f,final int howMany)
{
if (f == null) throw new IllegalArgumentException("f");
if(howMany<1) throw new IllegalArgumentException("howMany");
final List output = new ArrayList(howMany);
for(int i=1; i<=howMany; ++i)
output.add(f.apply(i));
return Collections.unmodifiableList(output);
}
/**
* See Map
* This is a 1-to-1 transformation. Every element in the input sequence will be transformed into an element in the output sequence.
* map: (A -> B) -> A list -> B list
* @param f a transformation function which takes a object of type A and returns an object, presumably related, of type B
* @param input a sequence to be fed into f
* @param the type of the element in the input sequence
* @param the type of the element in the output sequence
* @return a list of type B containing the transformed values.
*/
public final static List map(final Func f, final Iterable extends A> input)
{
final List output = input instanceof Collection> ? new ArrayList(((Collection) input).size()) : new ArrayList();
for(final A a : input)
output.add(f.apply(a));
return Collections.unmodifiableList(output);
}
/**
* See Map
* This is a 1-to-1 transformation. Every element in the input sequence will be transformed into an element in the output sequence.
* map: (A -> B) -> A list -> B list
* @param f a transformation function which takes a object of type A and returns an object, presumably related, of type B
* @param the type of the element in the input sequence
* @param the type of the element in the output sequence
* @return a curried function that expects an input sequence which it feeds to the transformation f which returns a list of type B
* containing the transformed values.
* @see Currying
*/
public final static Func,List> map(final Func super A, ? extends B> f)
{
return new Func, List>() {
@Override
public List apply(final Iterable input) {
return Functional.map(f,input);
}
};
}
/**
* See Map
* This is a 1-to-1 transformation. Every element in the input sequence will be transformed into an element in the output sequence.
* mapi: (int -> A -> B) -> A list -> B list
* @param f a transformation function which is passed each input object of type A along with its position in the input sequence
* (starting from zero) and returns an object, presumably related, of type B
* @param input a sequence to be fed into f
* @param the type of the element in the input sequence
* @param the type of the element in the output sequence
* @return a list of type B containing the transformed values.
*/
public final static List mapi(final Func2 f, final Iterable extends A> input)
{
final List output = input instanceof Collection> ? new ArrayList(((Collection) input).size()) : new ArrayList();
int pos = 0;
for(final A a : input)
output.add(f.apply(pos++, a));
return Collections.unmodifiableList(output);
}
/**
* See Map
* This is a 1-to-1 transformation. Every element in the input sequence will be transformed into an element in the output sequence.
* mapi: (int -> A -> B) -> A list -> B list
* @param f a transformation function which is passed each input object of type A along with its position in the input sequence
* (starting from zero) and returns an object, presumably related, of type B
* @param the type of the element in the input sequence
* @param the type of the element in the output sequence
* @return a curried function that expects an input sequence which it feeds to the transformation f which returns a list of type B
* containing the transformed values.
* @see Currying
*/
public final static Func,List> mapi(final Func2 f)
{
return new Func, List>() {
@Override
public List apply(final Iterable input) {
return Functional.mapi(f,input);
}
};
}
/// sortWith: (A -> A -> int) -> A list -> A list
/**
* sortWith: a wrapper for Collections.sort which preserves the input sequence.
* @param f the Comparator to use for the sort
* @param input the input
* @param the type of the Comparator
* @param the type of the element in the input sequence
* @return a sorted list containing all the elements of 'input' sorted using Collections.sort and 'f'
*/
public final static List sortWith(final Comparator f, final List input)
{
final List output = new ArrayList(input);
Collections.sort(output, f);
return Collections.unmodifiableList(output);
}
/**
* A simple function which wraps left.compareTo(right) so that this can be used as a sort function.
* @param left input element
* @param right input element
* @param the type of the elements to be compared
* @return left.compareTo(right)
*/
public final static >int Sorter(final A left, final A right)
{
return left.compareTo(right);
}
/**
* A Comparator that encapsulates Sorter above
*/
public final static Comparator dSorter = new Comparator()
{
@Override public int compare(final Integer i, final Integer j) { return Sorter(i, j); }
};
/**
* A wrapper around toString()
* @param a the element to be turned into a string using T.toString()
* @param the type of element 'a'
* @return a.toString()
*/
public final static String Stringify(final T a) { return a.toString(); }
/**
* A transformation function that wraps Stringify
* @param the type of the element which we will render as a String
* @return a function that calls Stringify
*/
public final static Func dStringify()
{
return new Func()
{
@Override public String apply(final T i) { return Stringify(i); }
};
}
/**
* forAll2: the predicate 'f' is applied to all elements in the input sequences input1 and input2 as pairs. If the predicate returns
* true for all pairs and there is the same number of elements in both input sequences then forAll2 returns true. If the predicate
* returns false at any point then the traversal of the input sequences halts and forAll2 returns false.
* forAll2: (A -> B -> bool) -> A list -> B list -> bool
* @param f predicate to which each successive pair (input1_i, input2_i) is applied
* @param input1 input sequence
* @param input2 input sequence
* @param the base type of the element in the first input sequence
* @param the base type of the element in the second input sequence
* @param the type of the element in the first input sequence
* @param the type of the element in the second input sequence
* @return true if the predicate 'f' evaluates true for all pairs, false otherwise
* @throws java.lang.IllegalArgumentException if the predicate returns true for all pairs and the sequences contain differing numbers
* of elements
*/
public final static boolean forAll2(final Func2 f, final Iterable input1, final Iterable input2)
{
final Iterator enum1 = input1.iterator();
final Iterator enum2 = input2.iterator();
boolean enum1Moved = false, enum2Moved = false;
do
{
enum1Moved = enum1.hasNext();
enum2Moved = enum2.hasNext();
if (enum1Moved && enum2Moved && !f.apply(enum1.next(), enum2.next()))
return false;
} while (enum1Moved && enum2Moved);
if( enum1Moved != enum2Moved)
throw new IllegalArgumentException();
return true;
}
/**
* See Filter
* @param pred a filter function. This is passed each input element in turn and returns either true or false. If true then
* the input element is passed through to the output otherwise it is ignored.
* @param input a sequence of objects
* @param the type of the element in the input sequence
* @return a list which contains zero or more of the elements of the input sequence. Each element is included only if the filter
* function returns true for the element.
*/
public final static List filter(final Func super A,Boolean> pred, final Iterable input)
{
final List output = input instanceof Collection> ? new ArrayList(((Collection) input).size()) : new ArrayList();
for(final A element : input)
if(pred.apply(element))
output.add(element);
return Collections.unmodifiableList(output);
}
/**
* See Filter
* @param f a filter function. This is passed each input element in turn and returns either true or false. If true then
* the input element is passed through to the output otherwise it is ignored.
* @param the type of the element in the input sequence
* @return a curried function that expects an input sequence which it feeds to the filter predicate which then returns
* a list which contains zero or more of the elements of the input sequence. Each element is included only if the filter
* function returns true for the element.
* @see Currying
*/
public static final Func,List> filter(final Func super T,Boolean> f)
{
return new Func, List>() {
@Override
public List apply(final Iterable input) {
return Functional.filter(f,input);
}
};
}
/**
* The converse operation to forAll. If the predicate returns true then 'exists' returns true and halts the traveral of the
* input sequence. Otherwise return false.
* exists: (A -> bool) -> A list -> bool
* @param f predicate
* @param input input sequence
* @param the type of the element in the input sequence
* @return true if the predicate returns true for any element in the input sequence, false otherwise
*/
public final static boolean exists(final Func super A,Boolean> f, final Iterable input)
{
for(final A a : input)
if(f.apply(a))
return true;
return false;
}
/**
* The converse operation to forAll. If the predicate returns true then 'exists' returns true and halts the traveral of the
* input sequence. Otherwise return false.
* exists: (A -> bool) -> A list -> bool
* This is the curried implementation.
* @param f predicate
* @param the type of the element in the input sequence
* @return true if the predicate returns true for any element in the input sequence, false otherwise
* @see Currying
*/
public final static Func,Boolean> exists(final Func super A,Boolean> f)
{
return new Func, Boolean>() {
@Override
public Boolean apply(final Iterable input) {
return Functional.exists(f,input);
}
};
}
/**
* not reverses the result of the applied predicate
* not: (A -> bool) -> (A -> bool)
* @param f the applied predicate
* @param the type of the input to the function f
* @return true if f returns false, false if f returns true
*/
public final static Func not(final Func f)
{
return new Func(){@Override public Boolean apply(final A a) { return !f.apply(a);}};
}
/**
* The converse operation to exists. If the predicate returns true for all elements in the input sequence then 'forAll'
* returns true otherwise return false.
* forAll: (A -> bool) -> A list -> bool
* @param f predicate
* @param input input sequence
* @param the type of the element in the input sequence
* @return true if the predicate returns true for all elements in the input sequence, false otherwise
*/
public final static boolean forAll(final Func f, final Iterable extends A> input)
{
return !exists(not(f), input);
}
/**
* The converse operation to exists. If the predicate returns true for all elements in the input sequence then 'forAll'
* returns true otherwise return false.
* forAll: (A -> bool) -> A list -> bool
* This is a curried implementation of 'forAll
* @param f predicate
* @param the type of the element in the input sequence
* @return true if the predicate returns true for all elements in the input sequence, false otherwise
* @see Currying
*/
public final static Func,Boolean> forAll(final Func super A,Boolean> f)
{
return new Func, Boolean>() {
@Override
public Boolean apply(final Iterable input) {
return Functional.forAll(f,input);
}
};
}
/**
* not2 reverses the result of the applied predicate
* not2: (A -> B -> bool) -> (A -> B -> bool)
* @param f the applied predicate
* @param the type of the first input to the function f
* @param the type of the second input to the function f
* @return true if f returns false, false if f returns true
*/
public final static Func2 not2(final Func2 f)
{
return new Func2(){@Override public Boolean apply(final A a, final B b) { return !f.apply(a,b);}};
}
///
/// (list * list). The first list contains all items for which f(a) is true. The second list contains the remainder.
/**
* partition is a group function. Given a predicate and an input sequence, 'partition' returns a pair of lists, the first list
* containing those elements from the input sequence for which the predicate returned true, the second list containing those
* elements from the input sequence for which the predicate returned false.
* partition: (A -> bool) -> A list -> A list * A list
* @param f predicate used to split the input sequence into two groups
* @param input the input sequence
* @param the type of the element in the input sequence
* @return a pair of lists, the first being the 'true' and the second being the 'false'
*/
public final static Pair,List> partition(final Func super A,Boolean> f, final Iterable input)
{
final List left;
final List right;
if(input instanceof Collection>)
{
left = new ArrayList(((Collection) input).size());
right = new ArrayList(((Collection) input).size());
}
else
{
left = new ArrayList();
right = new ArrayList();
}
for (final A a : input)
if (f.apply(a))
left.add(a);
else
right.add(a);
return new Pair,List>(Collections.unmodifiableList(left), Collections.unmodifiableList(right));
}
/**
* partition is a group function. Given a predicate and an input sequence, 'partition' returns a pair of lists, the first list
* containing those elements from the input sequence for which the predicate returned true, the second list containing those
* elements from the input sequence for which the predicate returned false.
* partition: (A -> bool) -> A list -> A list * A list
* This is a curried implementation of 'forAll
* @param f predicate used to split the input sequence into two groups
* @param the type of the element in the input sequence
* @return a pair of lists, the first being the 'true' and the second being the 'false'
* @see Currying
*/
public final static Func,Pair,List>> partition(final Func super A,Boolean> f)
{
return new Func, Pair, List>>() {
@Override
public Pair, List> apply(final Iterable input) {
return Functional.partition(f,input);
}
};
}
/**
* choose: this is a map transformation with the difference being that the number of elements in the output sequence may
* be between zero and the number of elements in the input sequence.
* See Map
* choose: (A -> B option) -> A list -> B list
* @param f map function. This transforms the input element into an Option
* @param input input sequence
* @param the type of the element in the input sequence
* @param the type of the element in the output sequence
* @return a list of transformed elements, numbering less than or equal to the number of input elements
*/
public final static List choose(final Func super A, Option> f, final Iterable input)
{
final List results = input instanceof Collection> ? new ArrayList(((Collection) input).size()) : new ArrayList();
for(final A a : input)
{
final Option intermediate = f.apply(a);
if (!intermediate.isNone())
results.add(intermediate.Some());
}
return Collections.unmodifiableList(results);
}
/**
* choose: this is a curried implementation of choose.
* choose is a map transformation with the difference being that the number of elements in the output sequence may
* be between zero and the number of elements in the input sequence.
* See Map
* choose: (A -> B option) -> A list -> B list
* @param f map function. This transforms the input element into an Option
* @param the type of the element in the input sequence
* @param the type of the element in the output sequence
* @return a list of transformed elements, numbering less than or equal to the number of input elements
* @see Currying
*/
public final static Func,List> choose(final Func super A, Option> f)
{
return new Func, List>() {
@Override
public List apply(final Iterable input) {
return Functional.choose(f,input);
}
};
}
/**
* See Fold
* fold: aggregate the elements of the input sequence given a seed and an aggregation function.
* fold: (A -> B -> A) -> A -> B list -> A
* @param f aggregation function
* @param initialValue seed for the algorithm
* @param input input sequence
* @param the type of the initialValue / seed
* @param the type of the element in the input sequence
* @return aggregated value
*/
public final static A fold(final Func2 super A, ? super B, ? extends A> f, final A initialValue, final Iterable input)
{
A state = initialValue;
for (final B b : input)
state = f.apply(state, b);
return state;
}
/**
* See Fold
* fold: aggregate the elements of the input sequence given a seed and an aggregation function.
* This is the curried implementation
* fold: (A -> B -> A) -> A -> B list -> A
* @param f aggregation function
* @param initialValue seed for the algorithm
* @param the type of the initialValue / seed
* @param the type of the element in the output sequence
* @return aggregated value
* @see Currying
*/
public final static Func,A> fold(final Func2 super A, ? super B, ? extends A> f, final A initialValue)
{
return new Func, A>() {
@Override
public A apply(final Iterable input) {
return Functional.fold(f,initialValue,input);
}
};
}
/**
* See Unfold and
* Anamorphism
* This is the converse of fold
* unfold: (b -> (a, b)) -> (b -> Bool) -> b -> [a]
*/
public final static List unfold(final Func super B,Pair> unspool, final Func super B,Boolean> finished, final B seed)
{
if(unspool==null) throw new IllegalArgumentException("unspool");
if(finished==null) throw new IllegalArgumentException("finished");
B next = seed;
final List results = new ArrayList();
while(!finished.apply(next)) {
final Pair t = unspool.apply(next);
results.add(t.getValue0());
next = t.getValue1();
}
return results;
}
/**
* See Unfold
* and Anamorphism
* This is the converse of fold
* unfold: (b -> (a, b)) -> (b -> Bool) -> b -> [a]
*/
public final static List unfold(final Func super B,Option>> unspool, final B seed)
{
if(unspool==null) throw new IllegalArgumentException("unspool");
B next = seed;
final List results = new ArrayList();
while(true) {
final Option> t = unspool.apply(next);
if(t.isNone()) break;
results.add(t.Some().getValue0());
next = t.Some().getValue1();
}
return results;
}
/**
* toDictionary: given each element from the input sequence apply the keyFn and valueFn to generate a (key,value) pair.
* The resulting dictionary (java.util.Map) contains all these pairs.
* @param keyFn function used to generate the key
* @param valueFn function used to generate the value
* @param input input sequence
* @param the type of the element in the input sequence
* @param the type of the key elements
* @param the type of the value elements
* @return a java.util.Map containing the transformed input sequence
* @throws IllegalArgumentException if some property of the specified key
* or value prevents it from being stored in this map
*/
public final static Map toDictionary(final Func super T,? extends K> keyFn, final Func super T,? extends V> valueFn, final Iterable input)
{
if(keyFn==null) throw new IllegalArgumentException("keyFn");
if(valueFn==null) throw new IllegalArgumentException("valueFn");
final Map output = new HashMap();
for(final T element : input) output.put(keyFn.apply(element), valueFn.apply(element));
return Collections.unmodifiableMap(output);
}
/**
* toArray: create an array containing all the objects in the input sequence
* @param input input sequence
* @param the type of the element in the input sequence
* @return an array containing all the elements of the input sequence
*/
public final static Object[] toArray(final Iterable input)
//public final static T[] toArray(final Iterable input)
{
if(input==null) throw new IllegalArgumentException("Functional.toArray(Iterable): input is null");
if(input instanceof Collection>)
return ((Collection)input).toArray();
final List output = new ArrayList();
for(final T element: input) output.add(element);
return output.toArray(); // this needs to be output.toArray(new T[0]) but that doesn't appear to be allowable Java :-(
}
public static final List toMutableList(final Iterable input)
{
if(input==null) throw new IllegalArgumentException("Functional.toMutableList(Iterable): input is null");
if(input instanceof Collection>)
{
final Collection input_ = (Collection)input;
final List output = new ArrayList(input_.size());
output.addAll(input_);
return output;
}
final List output = new ArrayList();
for(final T element: input) output.add(element);
return output;
}
public static final Map toMutableDictionary(final Map input)
{
if(input==null) throw new IllegalArgumentException("Functional.toMutableDictionary(Map): input is null");
final Map output = new HashMap(input.size());
output.putAll(input);
return output;
}
public static final Set toMutableSet(final Iterable input)
{
if(input==null) throw new IllegalArgumentException("Functional.toMutableSet(Iterable): input is null");
if(input instanceof Collection>)
{
final Collection input_ = (Collection)input;
final Set output = new HashSet(input_.size());
output.addAll(input_);
return output;
}
final Set