
jedi.functional.FunctionalPrimitives Maven / Gradle / Ivy
package jedi.functional;
import jedi.assertion.AssertionError;
import jedi.functors.ComposeableFunctor;
import jedi.functors.IdentityFunctor;
import jedi.option.None;
import jedi.option.Option;
import jedi.option.Options;
import jedi.option.Some;
import jedi.tuple.Tuple2;
import jedi.tuple.Tuples;
import java.util.*;
import static jedi.assertion.Assert.*;
import static jedi.functional.Coercions.*;
import static jedi.functional.Comparables.sort;
import static jedi.functional.Comparables.sortInPlace;
import static jedi.functional.FirstOrderLogic.invert;
import static jedi.functors.ComposeableFunctor.composeable;
import static jedi.option.Options.option;
import static jedi.option.Options.some;
import static jedi.tuple.Tuples.pair;
/**
* I provide operations of the kind found in Functional Programming languages.
* This allows you to remove a great deal of clutter from production code.
* Ideally, you will never need to write another 'for' loop again, and a great
* deal of explicit conditional logic should be removable as well.
*
* Generally, functions that transform collections (using functors or whatever)
* preserve the iteration order of the given collection in the result.
*/
public class FunctionalPrimitives {
private FunctionalPrimitives() {
}
private static final Comparator COLLECTION_SIZE_COMPARATOR = new Comparator() {
public int compare(Collection o1, Collection o2) {
return o1.size() - o2.size();
}
};
private static void addToGroup(final K key, final V value, final Map> groups) {
List group = groups.get(key);
if (group == null) {
groups.put(key, group = new ArrayList());
}
group.add(value);
}
private static Collection toCollection(Iterable iterable) {
return iterable instanceof Collection ? (Collection) iterable : asList(iterable);
}
private static List toList(Iterable iterable) {
return iterable instanceof List ? (List) iterable : asList(iterable);
}
/**
* Append all of the elements in all of the given collections
* into one list. All of the elements of the first item in
* collections
are appended first, then the items in the second
* collection, etc.
*
* @see #append(Iterable...)
*/
public static List append(final Iterable extends Iterable extends T>> iterables) {
List result = new ArrayList();
for (Iterable extends T> iter : iterables) {
addAll(result, iter);
}
return result;
}
/**
* Append all of the elements in all of the given collections
* into one list. All of the elements of the first item in
* collections
are appended first, then the items in the second
* collection, etc. Equivalent to {@link #append(Iterable)} ({@link Coercions#list(Object...) list}(iterables))
.
*
* @see #append(Iterable)
* @see Coercions#list(Object...)
*/
public static List append(final Iterable extends T>... iterables) {
return append(list(iterables));
}
/**
* Apply functor
to each element of items
and
* return the list of results.
*
* @see #collect(Object[],Functor)
*/
public static List collect(final Iterable items, final Functor super T, R> functor) {
assertNotNull(items, "items must not be null");
assertNotNull(functor, "functor must not be null");
final List mapped = new ArrayList();
for (final T item : items) {
mapped.add(functor.execute(item));
}
return mapped;
}
/**
* Apply functor
to each element of items
and
* return the list of results. The iteration order of items
is
* preserved in the returned list.
*
* Equivalent to collect(functor, asList(items))
*
* @see #collect(Iterable, Functor)
*/
public static List collect(final T[] items, final Functor super T, R> functor) {
return collect(asList(items), functor);
}
/**
* @see #collect(Iterable, Functor)
*/
public static List map(List list, Functor super T, R> functor) {
return collect(list, functor);
}
/**
* @see #collect(Iterable, Functor)
*/
public static Set map(Set set, Functor super T, R> functor) {
return Coercions.asSet(collect(set, functor));
}
/**
* Get all but the first n elements of
* items. See SRFI-1
*/
public static List drop(final int n, final Iterable items) {
assertNotNull(items, "items must not be null");
ArrayList list = new ArrayList();
int i = 0;
for (T t : items) {
if (i >= n) {
list.add(t);
}
i++;
}
return list;
}
/**
* Get all but the last n elements of items
. See SRFI-1
*/
public static List dropRight(final int n, final Iterable items) {
assertNotNull(items, "items must not be null");
Collection collection = toCollection(items);
assertLessThanOrEqualTo(collection.size(), n, "n should be less than or equal to items.size but is not");
return take(collection.size() - n, collection);
}
/**
* Suppose there is a collection of items (c1, c2, c3), each of which
* contains a collection i.e. (c1 = (c1_1, c1_2, ...), c2=(c2_1,
* c2_2, ...). I can produce a collection containing all of the 'leaf' items
* applied to functor
* i.e.(c1_1, c1_2, ..., c2_1, c2_2)
* Synonymous with {@link #flatMap(Iterable, Functor)}
*
Equivalent to {@link #append(Iterable) append}({@link #collect(Iterable, Functor) collect}(items, functor))
*
* @param items
* The collection of items containing the collection of leaves
* @param functor
* Given an element of the 'top' collection, this can obtain the
* collection of 'leaf' objects to accumulate
*/
public static List flatten(final Iterable items, final Functor super T, ? extends Iterable extends R>> functor) {
return append(collect(items, functor));
}
/**
* Given a collection of items (c1, c2, c3), each of which
* contains a collection i.e. (c1 = (c1_1, c1_2, ...), c2=(c2_1,
* c2_2, ...). I produce a collection containing all of the 'leaf' items
* i.e.(c1_1, c1_2, ..., c2_1, c2_2).
* Equivalent to {@link #flatten(Iterable, Functor)} and
* {@link #flatMap(Iterable, Functor)} with the {@link IdentityFunctor}
*
* @param items
* The collection of items containing the collection of leaves
*/
public static List flatten(Iterable extends Iterable> items) {
return flatten(items, IdentityFunctor.>identity());
}
/**
* Add all the elements of an iterable to a collection.
*/
public static Collection addAll(Collection list, Iterable extends T> iterable) {
assertNotNull(list, "list must not be null");
assertNotNull(iterable, "iterable must not be null");
for (T object : iterable) {
list.add(object);
}
return list;
}
/**
* Fold passes each item of a collection with an accumulated value to a
* functor.
*
* For example, to sum the elements of a list:
*
*
*
* Functor2<Integer, Integer, Integer> summer = new Functor2<Integer, Integer, Integer>() {
* public Integer execute(Integer accumulator, Integer value) {
* return accumulator + value;
* }
* };
* fold(10, summer, list(1, 2, 3, 4)) will return 20 (initial value of 10 + the sum of 1 .. 4)
*
*
*
* For a more comprehensive description, see SRFI-1
* @param initialValue the initial value for the fold
* @param collection the collection over which to fold
* @param functor2 the function to apply to values of the collection collected in Acc
*/
public static Acc fold(final InitialValue initialValue, final Iterable collection, final Functor2 functor2) {
assertNotNull(collection, "collection must not be null");
assertNotNull(functor2, "functor2 must not be null");
Acc accumulated = initialValue;
for (final T t : collection) {
accumulated = functor2.execute(accumulated, t);
}
return accumulated;
}
/**
* Reduce passes each item of a collection with an accumulated value to a functor yielding a single result.
* The first value from the collection applied to the functor is used as the initial accumulator value.
*
* For example, to sum the elements of a non-empty list:
*
*
*
* Functor2<Integer, Integer, Integer> summer = new Functor2<Integer, Integer, Integer>() {
* public Integer execute(Integer accumulator, Integer value) {
* return accumulator + value;
* }
* };
* reduce(summer, list(1, 2, 3, 4)) will return 10
*
*
*
* For a more comprehensive description, see SRFI-1
* @param collection the collection over which to fold
* @param functor2 the function to apply to values of the collection collected in Acc
*/
public static Acc reduce(final Iterable collection, final Functor2 functor2) {
assertNotNull(collection, "collection must not be null");
assertNotNull(functor2, "functor2 must not be null");
assertTrue(hasItems(collection), "items must not be empty");
return fold(head(collection), tail(collection), functor2);
}
/**
* Iterate over a collection of items
applying the given
* command
to each
*/
public static Iterable forEach(final Iterable items, final Command super T> command) {
assertNotNull(command, "command must not be null");
assertNotNull(items, "items must not be null");
for (final T item : items) {
command.execute(item);
}
return items;
}
/**
* A synonym for {@link #partition(Iterable, Functor)} Group the elements of
* a collection such that all elements that are mapped to the same value by
* a given keyFunctor
are in the same group. The groups are
* returned as a map in which each value is a collection of values in one
* group and whose key is the value returned by the keyFunctor
* for all items in the group.
*/
public static Map> group(final Iterable toGroup, final Functor super V, K> keyFunctor) {
assertNotNull(keyFunctor, "keyFunctor must not be null");
assertNotNull(toGroup, "toGroup must not be null");
final Map> groups = new HashMap>();
for (final V v : toGroup) {
addToGroup(keyFunctor.execute(v), v, groups);
}
return groups;
}
/**
* A synonym for {@link #group(Iterable, Functor)} Partition the elements of
* a collection such that all elements that are mapped to the same value by
* a given keyFunctor
are in the same partition. The groups are
* returned as a map in which each value is a collection of values in one
* partition and whose key is the value returned by the
* keyFunctor
for all items in the group.
*/
public static Map> partition(final Iterable toPartition, final Functor super V, K> keyFunctor) {
return group(toPartition, keyFunctor);
}
/**
* Get the first item (in iteration order) from a collection. The collection
* must contain at least one item or an
* {@link jedi.assertion.AssertionError AssertionError} will be thrown.
*
* @return the first item in the collection
* @throws jedi.assertion.AssertionError
* if the collection is empty
* @see #only(Collection)
* @see #headOrNullIfEmpty(Iterable)
* @see #headOrDefaultIfEmpty(Iterable, Object)
*/
public static T head(final Iterable items) {
assertNotNull(items, "items must not be null");
assertTrue(hasItems(items), "items must not be empty");
return headOrNullIfEmpty(items);
}
/**
* Get the first item (in iteration order) from a collection or
* defaultValue
(which may be null) if the collection is empty.
*
* @return the first item in the collection or defaultValue
if
* the collection is empty
* @see #only(Collection)
* @see #head(Iterable)
* @see #headOrNullIfEmpty(Iterable)
*/
public static T headOrDefaultIfEmpty(final Iterable extends T> items, final T defaultValue) {
assertNotNull(items, "items must not be null");
if (isEmpty(items)) {
return defaultValue;
}
if (items instanceof List) {
return ((List extends T>) items).get(0);
}
return items.iterator().next();
}
/**
* Get the first item (in iteration order) from a collection or
* null
if the collection is empty.
*
* @return the first item in the collection or null if the collection is
* empty
* @see #only(Collection)
* @see #head(Iterable)
* @see #headOrDefaultIfEmpty(Iterable, Object)
*/
public static T headOrNullIfEmpty(final Iterable items) {
return headOrDefaultIfEmpty(items, null);
}
/**
* Get the first item (in iteration order) from a collection as an
* {@link Option}.
*
* @param items
* @return the first item (in iteration order) from a collection as
* {@link Some} or {@link None} if the collection is empty.
*/
public static Option headOption(final Iterable items) {
return option(headOrNullIfEmpty(items));
}
/**
* Get the last item (in iteration order) from a collection. The collection
* must contain at least one item or an
* {@link jedi.assertion.AssertionError AssertionError} will be thrown.
*
* @return the last item in the collection
* @throws jedi.assertion.AssertionError
* if the collection is empty
* @see #only(Collection)
* @see #lastOrNullIfEmpty(Iterable)
* @see #lastOrDefaultIfEmpty(Iterable, Object)
*/
public static T last(Iterable extends T> items) {
assertNotNull(items, "items must not be null");
assertTrue(hasItems(items), "items must not be empty");
return lastOrNullIfEmpty(items);
}
/**
* Get the last item (in iteration order) from a collection or
* defaultValue
(which may be null) if the collection is empty.
*
* @return the last item in the collection or defaultValue
if
* the collection is empty
* @see #only(Collection)
* @see #last(Iterable)
* @see #lastOrNullIfEmpty(Iterable)
*/
public static T lastOrDefaultIfEmpty(Iterable extends T> items, T defaultValue) {
assertNotNull(items, "items must not be null");
if (isEmpty(items)) {
return defaultValue;
}
List extends T> l = toList(items);
return l.get(l.size() - 1);
}
public static T lastOrNullIfEmpty(Iterable extends T> items) {
return lastOrDefaultIfEmpty(items, null);
}
/**
* Get the last item (in iteration order) from a collection as an
* {@link Option}.
*
* @return the last item as a {@link Some} or {@link None} if the collection
* is empty.
*/
public static Option lastOption(Collection extends T> items) {
return option(lastOrNullIfEmpty(items));
}
/**
* An alias for head
*
* @see #head(Iterable)
*/
public static T first(Iterable extends T> collection) {
return head(collection);
}
/**
* Find the first item that matches the given filter
* @return The first item that matches the given filter
* @throws AssertionError if no match can be found
*/
public static T first(Iterable all, final Filter super T> filter) {
for (T t : all) {
if(filter.execute(t)) {
return t;
}
}
throw new AssertionError("At least one item should match the filter");
}
/**
* Find the first item that matches the given filter or null if no match can be found
* @return The first item that matches the given filter or null if no match can be found
*/
public static T firstOrDefault(Iterable extends T> all, final Filter super T> filter, T defaultValue) {
for (T t : all) {
if(filter.execute(t)) {
return t;
}
}
return defaultValue;
}
/**
* Find the first item that matches the given filter or null if no match can be found
* @return The first item that matches the given filter or null if no match can be found
*/
public static T firstOrNull(Iterable all, final Filter super T> filter) {
return firstOrDefault(all, filter, null);
}
/**
* Find the first item that matches the given filter
* @return A Some Option on the first matching item or None if no items match
*/
public static Option firstOption(Iterable all, final Filter super T> filter) {
return Options.option(firstOrNull(all, filter));
}
/**
* Get the first item (in iteration order) from a collection as an
* {@link Option}.
*
* @param items
* @return the first item (in iteration order) from a collection as
* {@link Some} or {@link None} if the collection is empty.
*/
public static Option firstOption(final Iterable items) {
return option(headOrNullIfEmpty(items));
}
/**
* An alias for fold.
*
* @see #fold(Object, Iterable, Functor2)
*/
public static R inject(final I initialValue, final Iterable collection, final Functor2 functor2) {
return fold(initialValue, collection, functor2);
}
/**
* Join, with default delimiter (empty string)
*
* @see #join(Object[], String)
*/
public static String join(final Iterable> items) {
return join(items, "");
}
public static String join(final Iterable> items, final String delimiter) {
assertNotNull(items, "items must not be null");
assertNotNull(delimiter, "delimiter must not be null");
Iterator> iterator = items.iterator();
final StringBuffer sb = new StringBuffer();
while (iterator.hasNext()) {
sb.append(iterator.next());
if (iterator.hasNext()) {
sb.append(delimiter);
}
}
return sb.toString();
}
/**
* Returns a string created by converting each element of an array to a
* string, separated by delimiter. Emulates Array.join in Ruby.
*/
public static String join(final Object[] items, final String delimiter) {
assertNotNull(items, "items must not be null");
return join(asList(items), delimiter);
}
/**
* Returns an n-element list. Element i of the list, where 0 <= i < n, is
* produced by the functor. For a more comprehensive description, see SRFI-1
*
* @param n
* the length of the list
* @param functor
* the functor taking an integer and returning an
*/
public static List listTabulate(final int n, final Functor functor) {
assertNotNull(functor, "functor must not be null");
final List list = new ArrayList(n);
for (int i = 0; i < n; i++) {
list.add(functor.execute(i));
}
return list;
}
/**
* Find the biggest collection in a collection of collections
*
* @param collections
* @return the shortest list
*/
public static > T longest(final Iterable collections) {
assertNotNull(collections, "collections must not be null");
assertTrue(hasItems(collections), "collections must have at least one item");
return head(reverse(sortInPlace(asList(collections), COLLECTION_SIZE_COMPARATOR)));
}
/**
* Returns an n-element list, whose elements are all the value
* fill
. For a more comprehensive description, see SRFI-1
*/
public static List makeList(final int n, final T fill) {
assertNotNull(fill, "fill must not be null");
final List list = new ArrayList(n);
for (int i = 0; i < n; i++) {
list.add(fill);
}
return list;
}
/**
* Return the one and only item in the given collection.
*
* @return the item in the collection
* @throws jedi.assertion.AssertionError
* if the collection contains less or more than one item
* @see #head(Iterable)
* @see #headOrNullIfEmpty(Iterable)
*/
public static T only(final Collection items) {
assertNotNull(items, "items must not be null");
assertEqual(1, items.size(), "items must contain only one element");
return head(items);
}
/**
* Create the Cartesian product of two collections, using a {@link Functor2
* functor} as a factory of objects to represent the pair-wise products.
*/
public static List produce(final Iterable left, final Iterable right, final Functor2 super T, ? super U, R> factory) {
final List product = new ArrayList();
for (final T t : left) {
for (final U u : right) {
product.add(factory.execute(t, u));
}
}
return product;
}
/**
* Filter a collection of items
, returning only those that do
* not match a given filter
, this is the inverse of select.
*
* @see #select(Iterable, Filter)
*/
public static List reject(final Iterable items, final Filter super T> filter) {
assertNotNull(filter, "filter must not be null");
assertNotNull(items, "items must not be null");
return select(items, invert(filter));
}
public static List reverse(final Iterable items) {
assertNotNull(items, "items must not be null");
List result = asList(items);
Collections.reverse(result);
return result;
}
/**
* Filter a collection of items
, returning only those that
* match a given filter
, this is the inverse of reject.
*
* @see #reject(Iterable, Filter)
*/
public static List select(final Iterable items, final Filter super T> filter) {
assertNotNull(filter, "filter must not be null");
assertNotNull(items, "items must not be null");
final List selected = new ArrayList();
for (final T item : items) {
if (filter.execute(item)) {
selected.add(item);
}
}
return selected;
}
/**
* Produce a single command that executes each of the given
* commands
in sequence
*/
public static Command sequence(final Command super T>... commands) {
return new Command() {
public void execute(final T value) {
for (final Command super T> command : commands) {
command.execute(value);
}
}
};
}
/**
* Find the shortest list in a list of lists
*
* @param collections
* @return the shortest list
*/
public static > T shortest(final Iterable collections) {
assertNotNull(collections, "lists must not be null");
assertTrue(hasItems(collections), "lists must have at least one item");
return head(sort(asList(collections), COLLECTION_SIZE_COMPARATOR));
}
public static boolean hasItems(final Iterable iterable) {
return iterable.iterator().hasNext();
}
public static boolean isEmpty(final Iterable iterable) {
return !hasItems(iterable);
}
/**
* Create a list from the nth elements of the given lists.
*/
public static List slice(final int n, final Iterable items) {
assertNotNull(items, "lists must not be null");
assertGreaterThanOrEqualTo(0, n, "n must be greater than or equal to 0");
final List result = new ArrayList();
for (final List list : items) {
result.add(list.get(n));
}
return result;
}
/**
* Create a list of string by splitting on a regex.
*
* @see java.lang.String#split(String)
*/
public static List split(final String item, final String regex) {
assertNotNull(item, "item must not be null");
assertNotNull(regex, "regex must not be null");
return asList(item.split(regex));
}
/**
* Get all item's (in iteration order) from a collection except the first.
* The collection must contain at least one item or an
* {@link jedi.assertion.AssertionError AssertionError} will be thrown.
*
* @return all items except the first
* @throws jedi.assertion.AssertionError
* if the collection contains less or more than one item
* @see #only(Collection)
* @see #headOrNullIfEmpty(Iterable)
* @see #headOrDefaultIfEmpty(Iterable, Object)
*/
public static List tail(final Iterable items) {
assertNotNull(items, "items must not be null");
assertTrue(hasItems(items), "items must not be empty");
return drop(1, items);
}
/**
* Get the first n elements of items.
*
* @see SRFI-1
*/
public static List take(final int n, final Iterable items) {
assertNotNull(items, "list must not be null");
List result = new ArrayList();
for (T item : items) {
if (result.size() == n) {
return result;
}
result.add(item);
}
assertEqual(n, result.size(), "There are not enough items to take");
return result;
}
/**
* Get the last n elements of an Iterable.
*
* @see SRFI-1
*/
public static List takeRight(final int n, final Iterable items) {
assertNotNull(items, "list must not be null");
List asList = toList(items);
assertLessThanOrEqualTo(asList.size(), n, "n must be less than or equal to list.size");
return drop(asList.size() - n, asList);
}
/**
* Get n middle elements of an Iterable.
*/
public static List takeMiddle(final int start, final int n, final Iterable items) {
assertNotNull(items, "list must not be null");
assertGreaterThanOrEqualTo(0, start, "start must not be negative");
assertGreaterThanOrEqualTo(0, n, "n must not be negative");
List result = new ArrayList();
int index = 0;
for (T item : items) {
if (result.size() == n) {
return result;
}
if (index >= start) {
result.add(item);
}
index++;
}
assertEqual(n, result.size(), "The given items has insufficient elements");
return result;
}
/**
* Zip interleaves a collection of lists. If zip is passed n lists, it
* returns a list as long as the shortest of these lists, each element of
* which is an n-element list comprised of the corresponding elements from
* the parameter lists.
*
*
* See SRFI-1
*
* @param lists
* @return zipped lists
*/
public static List zip(final Iterable lists) {
final int n = shortest(lists).size();
final List result = new ArrayList();
for (int i = 0; i < n; i++) {
result.add(slice(i, lists));
}
return result;
}
/**
* Zips two lists returning a List of Tuple2.
* The returned list's length is the smallest of listA and listB
*/
public static List> zip(final List listA, final List listB) {
final int n = shortest(list(listA, listB)).size();
final List> result = new ArrayList>();
for (int i = 0; i < n; i++) {
result.add(Tuples.pair(listA.get(i), listB.get(i)));
}
return result;
}
/**
* ZipWithIndex Zips this list with its indices.
* For example list("a", "b", "c").zipWithIndex = List(("a", 0), ("b", 1), ("c", 2))
* where (x,y) is a {@link Tuple2}.
* @return a list of Tuple2 containing elements of list and their index in the list.
*/
public static List> zipWithIndex(final List list) {
final List> result = new ArrayList>();
for (int i = 0; i < list.size(); i++) {
result.add(new Tuple2(list.get(i), i));
}
return result;
}
/**
* @return a list of lists by splitting the given list into lists of length
* length
.
*/
public static List> tabulate(final Iterable list, int length) {
List line = toList(list);
assertTrue(line.size() % length == 0, "size must be a multiple of length", line, length);
List> result = new ArrayList>(line.size());
for (int i = 0; i < line.size(); i += length) {
result.add(takeMiddle(i, length, line));
}
return result;
}
/**
* Removes the last item (in iteration order) from a collection.
* The collection must contain at least one item or an
* {@link jedi.assertion.AssertionError AssertionError} will be thrown.
* Emulates Array.pop in Ruby.
*
* The original collection is unaltered.
*
* @return the last item in the collection
* @throws jedi.assertion.AssertionError
* if the collection is empty
* @see #only(Collection)
* @see #headOrNullIfEmpty(Iterable)
* @see #headOrDefaultIfEmpty(Iterable, Object)
*/
public static T pop(Iterable items) {
List list = toList(items);
assertNotNullOrEmpty(list, "items must not be null or empty");
return list.remove(list.size() - 1);
}
/**
* Removes the last item (in iteration order) from a collection as an
* {@link Option}.
*
* @return the last item in the collection as {@link Some} or {@link None}
* if the list is empty.
*/
public static Option popOption(Iterable items) {
return isEmpty(items) ? Options. none() : some(pop(items));
}
/**
* Partition a collection of items into two sublists using the given filter.
*
* @param items
* @return a list whose first element as a list of items in list that pass
* the filter, the second item is a list of elements that did not
* pass the filter.
*/
public static Tuple2, List> partition(Iterable items, Filter filter) {
return pair(select(items, filter), select(items, invert(filter)));
}
/**
* Return the set of all subsets of the provided collection.
*
* For example, if all is the list ("x","y","z"), the return will be set containing
* 8 lists as follows:
*
*
* - () - empty set
* - ("x")
* - ("y")
* - ("z")
* - ("x","y")
* - ("x","z")
* - ("y","z")
* - ("x","y","z")
*
*
* See http://en.wikipedia.org/wiki/Power_set
*
* @see #powerset(Collection, Command)
* @see #foldPowerset(Object, Collection, Functor2)
*
*/
public static Set> powerset(Collection all) {
assertNotNull(all, "all must not be null");
return all.isEmpty() ? set(Collections.emptyList()) : nonDegeneratePowerSet(all);
}
private static Set> nonDegeneratePowerSet(Collection all) {
Set> powerset = new HashSet>();
int howManySubsetsInThePowerSet = 2 << (all.size() - 1);
for(int i = 0 ; i != howManySubsetsInThePowerSet ; i++) {
List currentSubset = createSubsetFromOriginalSet(all, i);
powerset.add(currentSubset);
}
return powerset;
}
private static List createSubsetFromOriginalSet(Iterable all, int elementsToIncludeBitMap) {
List current = new ArrayList();
int remainingElementsToInclude = elementsToIncludeBitMap;
for (T t : all) {
if ((remainingElementsToInclude & 1) == 1) {
current.add(t);
}
remainingElementsToInclude >>= 1;
}
return current;
}
/**
* Iterate all powersets of the give collection, in no particular order.
* @see #powerset(Collection)
* @see #foldPowerset(Object, Collection, Functor2)
*/
public static void powerset(Collection all, Command> command) {
assertNotNull(all, "all must not be null");
assertNotNull(command, "command must not be null");
recursePowerset(Collections.emptyList(), asList(all), command);
}
private static void recursePowerset(List prefix, List tail, Command> command) {
command.execute(prefix);
for (int i = 0 ; i < tail.size() ; i++) {
recursePowerset(append(prefix, list(tail.get(i))), tail.subList(i + 1, tail.size()), command);
}
}
/**
* Fold over all powersets of the give collection, in no particular order.
* @see #powerset(Collection)
* @see #powerset(Collection, Command)
* @see #fold(Object, Iterable, Functor2)
*/
public static R foldPowerset(I initialValue, Collection all, final Functor2, R> functor2) {
assertNotNull(all, "all must not be null");
assertNotNull(functor2, "functor2 must not be null");
return recursePowerset(initialValue, Collections.emptyList(), asList(all), functor2);
}
private static R recursePowerset(I initialValue, List prefix, List tail, final Functor2, R> functor2) {
R value = functor2.execute(initialValue, prefix);
for (int i = 0 ; i < tail.size() ; i++) {
value = recursePowerset(value, append(prefix, list(tail.get(i))), tail.subList(i + 1, tail.size()), functor2);
}
return value;
}
/**
* Builds a new collection by applying a function to all elements of list and concatenating the results.
* Synonymous with {@link #flatten(Iterable, Functor)}
* @param iter the collection to map
* @param functor a functor yielding a collection from the application of an element from iter
* @return a flattened List
*/
public static List flatMap(Iterable iter, final Functor super T, ? extends Iterable extends R>> functor) {
return flatten(iter, functor);
}
/**
* Curries f2 with f0 returning a functor taking a single argument.
* For example, given a Functor2, f2, that sums its integer arguments, and a Functor0, f0, that returns 3,
* curry(f2, f0) gives a Functor that accepts a single integer, v, and returns 3 + v.
* f0 needn't be a constant, it could be any function that returns an appropriate result for f2's consumption.
* @param f2
* @param f0
*/
public static ComposeableFunctor curry(final Functor2 f2, final Functor0 extends T> f0) {
return composeable(new Functor() {
public R execute(U value) {
return f2.execute(f0.execute(), value);
}
});
}
/**
* Find the 0-based index of the first value of a collection satisfying the filter.
* @param all
* @param filter
* @param
* @return the 0-based index of the first value of a all
satisfying filter
or -1
*/
public static int indexWhere(Iterable all, final Filter super T> filter) {
int c = 0;
for (T t : all) {
if (filter.execute(t)) return c;
c += 1;
}
return -1;
}
/**
* Find the 0-based index of the last value of a collection satisfying the filter.
* @param all
* @param filter
* @param
* @return the 0-based index of the last value of a all
satisfying filter
or -1
*/
public static int lastIndexWhere(Iterable all, final Filter super T> filter) {
List reversed = reverse(all);
int i = indexWhere(reversed, filter);
return i == -1 ? -1 : reversed.size() -1 - i;
}
}