me.shaftesbury.utils.functional.Functional Maven / Gradle / Ivy
/**
* Created with IntelliJ IDEA.
* User: Bob
* Date: 16/10/13
* Time: 20:04
* To change this template use File | Settings | File Templates.
*/
/**
* Created with IntelliJ IDEA.
* User: Bob
* Date: 16/10/13
* Time: 20:04
* To change this template use File | Settings | File Templates.
*/
package me.shaftesbury.utils.functional;
import org.javatuples.Pair;
import org.javatuples.Triplet;
import java.util.*;
public final class Functional
{
private Functional() {}
public final static boolean isNullOrEmpty(final String s)
{
return s==null || s.isEmpty();
}
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();
}
public final static String indentBy(final int howMany, final String unitOfIndentation, final String indentThis)
{
final Collection indentation = init(
new Func() {
@Override
public String apply(Integer integer) {
return unitOfIndentation;
}
}, howMany);
return fold(new Func2() {
@Override
public String apply(String state, String str) {
return str + state;
}
}, indentThis, indentation);
}
public final static Pair> foldAndChoose(
final me.shaftesbury.utils.functional.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, new UnmodifiableList(results));
}
public static final List toList(final Enumeration input)
{
final List output = new ArrayList();
while(input.hasMoreElements())
output.add(input.nextElement());
return new UnmodifiableList(output);
}
///
/// Analogue of string.Join for List<T> with the addition of a user-defined map function
///
///
///
///
///
///
public final static String join(final String separator, final Iterable l, final Func fn)
{
if (l == null) throw new IllegalArgumentException("l");
if (fn == null) throw new IllegalArgumentException("fn");
return join(separator, map(fn,l));
}
/// 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: (A -> bool) -> A list -> A
public final static A find(Func f, 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 KeyNotFoundException();
}
public final static Func,A> find(final Func f)
{
return new Func, A>() {
@Override
public A apply(Iterable input) {
return Functional.find(f,input);
}
};
}
/// findIndex: (A -> bool) -> A list -> int
public static int findIndex(Func f, Iterable 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();
}
/// findLast: (A -> bool) -> A list -> A
public final static A findLast(final Func 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 KeyNotFoundException();
}
/// findLast: (A -> bool) -> A list -> A
public final static A findLast(final Func f, final List input)
{
if (f == null) throw new IllegalArgumentException("f");
if (input == null) throw new IllegalArgumentException("input");
for (final A a : Enumerators.ReverseEnum(input))
if (f.apply(a))
return a;
throw new KeyNotFoundException();
}
public final static Func,A> findLast(final Func f)
{
return new Func, A>() {
@Override
public A apply(List input) {
return Functional.findLast(f,input);
}
};
}
/// pick: (A -> B option) -> A list -> B
public static B pick(final Func> f, final Iterable 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 KeyNotFoundException();
}
public static Func,B> pick(final Func> f)
{
return new Func, B>() {
@Override
public B apply(final Iterable input) {
return Functional.pick(f,input);
}
};
}
public final static B In( final A input, final Func f)
{
return f.apply(input);
}
public final static Func Then(final Func f, final Func g)
{
return new Func()
{
@Override
public C apply(A x)
{
return g.apply(f.apply(x));
}
};
}
public final static Func Identity()
{
return new Func() {
@Override
public T apply(T t) {
return t;
}
};
}
public static final Func IsEven = new Func()
{
@Override
public Boolean apply(Integer i)
{
return i % 2 == 0;
}
};
public static final Func IsOdd = new Func()
{
@Override
public Boolean apply(Integer i)
{
return i % 2 != 0;
}
};
public static final me.shaftesbury.utils.functional.Func2 Count =
new Func2() {
@Override
public Integer apply(Integer state, Integer b) {
return state + 1;
}
};
/// init: int -> (int -> A) -> A list
public final static List init(final Func f,final int howMany)
{
//if (f == null) throw new ArgumentNullException("f");
final List output = new ArrayList();
for(int i=0; i map: (A -> B) -> A list -> B list
public final static List map(final Func f, final Iterable input)
{
final List output = new ArrayList();
for(final A a : input)
output.add(f.apply(a));
return new UnmodifiableList(output);
}
public final static Func,List> map(final Func f)
{
return new Func, List>() {
@Override
public List apply(Iterable input) {
return Functional.map(f,input);
}
};
}
/// sortWith: (A -> A -> int) -> A list -> A list
public final static List sortWith(final Comparator f, final List input)
{
final List output = new ArrayList(input);
Collections.sort(output, f);
return new UnmodifiableList(output);
}
public final static >int Sorter(final A left, final A right)
{
return left.compareTo(right);
}
public final static Comparator dSorter = new Comparator()
{
@Override public int compare(Integer i, Integer j) { return Sorter(i, j); }
};
public final static String Stringify(final T a) { return a.toString(); }
public final static Func dStringify()
{
return new Func()
{
@Override public String apply(T i) { return Stringify(i); }
};
}
/// forAll2: (A -> B -> bool) -> A list -> B list -> bool
public final static boolean forAll2(final me.shaftesbury.utils.functional.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;
}
public final static List filter(final Func pred, final Iterable input)
{
final List output = new ArrayList();
for(final A element : input)
{
if(pred.apply(element))
output.add(element);
}
return new UnmodifiableList(output);
}
public static final Func,List> filter(final Func f)
{
return new Func, List>() {
@Override
public List apply(final Iterable input) {
return Functional.filter(f,input);
}
};
}
/// exists: (A -> bool) -> A list -> bool
public final static boolean exists(final Func f, final Iterable input)
{
for(final A a : input)
if(f.apply(a))
return true;
return false;
}
public final static Func,Boolean> exists(final Func f)
{
return new Func, Boolean>() {
@Override
public Boolean apply(Iterable input) {
return Functional.exists(f,input);
}
};
}
/// not: (A -> bool) -> (A -> bool)
public final static Func not(final Func f)
{
return new Func(){@Override public Boolean apply(A a) { return !f.apply(a);}};
}
/// forAll: (A -> bool) -> A list -> bool
public final static boolean forAll(final Func f, final Iterable input)
{
return !exists(not(f), input);
}
public final static Func,Boolean> forAll(final Func f)
{
return new Func, Boolean>() {
@Override
public Boolean apply(Iterable input) {
return Functional.forAll(f,input);
}
};
}
/// not2: (A -> B -> bool) -> (A -> B -> bool)
public final static me.shaftesbury.utils.functional.Func2 not2(final me.shaftesbury.utils.functional.Func2 f)
{
return new Func2(){@Override public Boolean apply(A a, B b) { return !f.apply(a,b);}};
}
/// partition: (A -> bool) -> A list -> A list * A list
/// (list * list). The first list contains all items for which f(a) is true. The second list contains the remainder.
public final static org.javatuples.Pair,List> partition(final Func f, final Iterable input)
{
final List left = new ArrayList();
final List right = new ArrayList();
for (final A a : input)
if (f.apply(a))
left.add(a);
else
right.add(a);
return new org.javatuples.Pair,List>(new UnmodifiableList(left), new UnmodifiableList(right));
}
public final static Func,org.javatuples.Pair,List>> partition(final Func f)
{
return new Func, Pair, List>>() {
@Override
public Pair, List> apply(Iterable input) {
return Functional.partition(f,input);
}
};
}
/// choose: (A -> B option) -> A list -> B list
public final static List choose(final Func> f, final Iterable input)
{
final List results = new ArrayList();
for(final A a : input)
{
final Option intermediate = f.apply(a);
if (!intermediate.isNone())
results.add(intermediate.Some());
}
return new UnmodifiableList(results);
}
public final static Func,List> choose(final Func> f)
{
return new Func, List>() {
@Override
public List apply(Iterable input) {
return Functional.choose(f,input);
}
};
}
/// fold: (A -> B -> A) -> A -> B list -> A
public final static A fold(final me.shaftesbury.utils.functional.Func2 f, final A initialValue, final Iterable input)
{
A state = initialValue;
for (final B a : input)
state = f.apply(state, a);
return state;
}
public final static Func,A> fold(final me.shaftesbury.utils.functional.Func2 f, final A initialValue)
{
return new Func, A>() {
@Override
public A apply(Iterable input) {
return Functional.fold(f,initialValue,input);
}
};
}
public final static Map toDictionary(final Func keyFn, final Func valueFn, 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 new UnmodifiableMap(output);
}
//public final static T[] toArray(final Iterable input)
public final static Object[] toArray(final Iterable input)
{
if(input==null) throw new IllegalArgumentException("Functional.toArray(Iterable): input is null");
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 toList(Iterable input)
{
if(input==null) throw new IllegalArgumentException("Functional.toList(Iterable): input is null");
if(input instanceof List>) return (List)input;
final List output = new ArrayList();
for(final T element: input) output.add(element);
return output;
}
public static final T last(final Iterable input)
{
if(input==null) throw new IllegalArgumentException("Functional.last(Iterable): input is null");
T state = null;
for(final T element: input) state = element;
return state;
}
public static final T last(final T[] input)
{
if(input==null||input.length==0) throw new IllegalArgumentException("Functional.last(Iterable): input is null or empty");
return input[input.length-1];
}
public static final List concat(final List list1, final List list2)
{
if(list1==null) throw new IllegalArgumentException("Functional.concat(List,List): list1 is null");
if(list2==null) throw new IllegalArgumentException("Functional.concat(List,List): list2 is null");
if(list1.size()==0) return new UnmodifiableList(list2);
if(list2.size()==0) return new UnmodifiableList(list1);
final List newList = new ArrayList(list1);
final boolean didItChange = newList.addAll(list2);
return new UnmodifiableList(newList);
}
public static finalList take(final int howMany, final Iterable list)
{
if(howMany<0) throw new IllegalArgumentException("Functional.take(int,Iterable): howMany is negative");
if(list==null) throw new IllegalArgumentException("Functional.take(int,Iterable): list is null");
if(howMany==0) return new ArrayList(0);
final List output = new ArrayList(howMany);
final Iterator iterator = list.iterator();
for(int i=0;iFunc,List> take(final int howMany)
{
return new Func, List>() {
@Override
public List apply(Iterable input) {
return Functional.take(howMany,input);
}
};
}
public static final Func Constant(final T constant)
{
return new Func() {
@Override
public T apply(Integer integer) {
return constant;
}
};
}
public static final List> zip(final Iterable l1, final Iterable l2)
{
if(l1==null) throw new IllegalArgumentException("Functional.zip(Iterable,Iterable): l1 is null");
if(l2==null) throw new IllegalArgumentException("Functional.zip(Iterable,Iterable): l2 is null");
final List> output = new ArrayList>();
final Iterator l1_it = l1.iterator();
final Iterator l2_it = l2.iterator();
while(l1_it.hasNext() && l2_it.hasNext()) output.add(new org.javatuples.Pair(l1_it.next(),l2_it.next()));
if(l1_it.hasNext() || l2_it.hasNext()) throw new IllegalArgumentException("Functional.zip(Iterable,Iterable): l1 and l2 have differing numbers of elements");
return new UnmodifiableList(output);
}
public static final List> zip3(final Iterable l1, final Iterable l2, final Iterable l3)
{
if(l1==null) throw new IllegalArgumentException("Functional.zip3(Iterable,Iterable,Iterable): l1 is null");
if(l2==null) throw new IllegalArgumentException("Functional.zip3(Iterable,Iterable,Iterable): l2 is null");
if(l3==null) throw new IllegalArgumentException("Functional.zip3(Iterable,Iterable,Iterable): l3 is null");
final List> output = new ArrayList>();
final Iterator l1_it = l1.iterator();
final Iterator l2_it = l2.iterator();
final Iterator l3_it = l3.iterator();
while(l1_it.hasNext() && l2_it.hasNext() && l3_it.hasNext()) output.add(new org.javatuples.Triplet(l1_it.next(),l2_it.next(),l3_it.next()));
if(l1_it.hasNext() || l2_it.hasNext() || l3_it.hasNext())
throw new IllegalArgumentException("Functional.zip3(Iterable,Iterable,Iterable): l1, l2 and l3 have differing numbers of elements");
return new UnmodifiableList(output);
}
public static final org.javatuples.Pair,List> unzip(final Iterable> input)
{
if(input==null) throw new IllegalArgumentException("Functional.unzip(Iterable>): input is null");
final List l1 = new ArrayList();
final List l2 = new ArrayList();
for(org.javatuples.Pair pair:input)
{
l1.add(pair.getValue0());
l2.add(pair.getValue1());
}
return new org.javatuples.Pair(new UnmodifiableList(l1),new UnmodifiableList(l2));
}
public static final Triplet,List,List> unzip3(final Iterable> input)
{
if(input==null) throw new IllegalArgumentException("Functional.unzip(Iterable>): input is null");
final List l1 = new ArrayList();
final List l2 = new ArrayList();
final List l3 = new ArrayList();
for(org.javatuples.Triplet triplet:input)
{
l1.add(triplet.getValue0());
l2.add(triplet.getValue1());
l3.add(triplet.getValue2());
}
return new org.javatuples.Triplet(new UnmodifiableList(l1),new UnmodifiableList(l2),new UnmodifiableList(l3));
}
public static final List collect(final Func> f, final Iterable input)
{
List output = new ArrayList();
for(final T element : input)
output = Functional.concat(output, Functional.toList(f.apply(element)));
return new UnmodifiableList(output);
}
public static final