package org.enumerable.lambda.enumerable; import static java.util.Arrays.*; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.regex.Pattern; import org.enumerable.lambda.Fn0; import org.enumerable.lambda.Fn1; import org.enumerable.lambda.Fn2; import org.enumerable.lambda.enumerable.collection.EList; import org.enumerable.lambda.enumerable.collection.EMap; import org.enumerable.lambda.enumerable.collection.ESet; /** * Ruby/Smalltalk style internal iterators for Java 5 using bytecode * transformation to capture expressions as closures. * * <p> * <a href="http://ruby-doc.org/core/classes/Enumerable.html"/>Ruby's Enumerable * module in 1.8.6</a> * </p> * <p> * <a href="http://ruby-doc.org/ruby-1.9/classes/Enumerable.html"/>Ruby's * Enumerable module in 1.9</a> * </p> * <p> * This class adapts the methods in {@link Enumerable} to work on arrays. */ public class EnumerableArrays { /** * Passes each element of the array to the given block. The method returns * true if the block never returns false or null. */ public static <E> boolean all(E[] array, Fn1<? super E, ?> block) { return Enumerable.all(asList(array), block); } /** * Passes each element of the array to the an implicit block of * {@link Fn1#identity()}. The method returns true if the block never * returns false or null. */ public static <E> boolean all(E[] array) { return Enumerable.all(asList(array)); } /** * Passes each element of the array to the given block. The method returns * true if the block ever returns a value other than false or null. */ public static <E> boolean any(E[] array, Fn1<? super E, ?> block) { return Enumerable.any(asList(array), block); } /** * Passes each element of the array to the an implicit block of * {@link Fn1#identity()}. The method returns true if the block ever returns * a value other than false or null. */ public static <E> boolean any(E[] array) { return Enumerable.any(asList(array)); } /** * Returns a new list with the results of running block once for every * element in array. */ public static <E, R> Object[] collect(E[] array, Fn1<? super E, R> block) { return Enumerable.collect(asList(array), block).toArray(); } /** * Returns a new list with the results of running block once for every * element in array. Takes an extra type parameter to handle empty arrays. */ @SuppressWarnings("unchecked") public static <E, R> R[] collect(E[] array, Fn1<? super E, R> block, Class<R> type) { return Enumerable.collect(asList(array), block).toArray((R[]) Array.newInstance(type, 0)); } /** * Returns the count of all elements in array. */ public static <E> int count(E[] array) { return array.length; } /** * Returns the count of objects in arry that equal obj. */ public static <E> int count(E[] array, E obj) { return Enumerable.count(asList(array), obj); } /** * Returns the count of objects in array for which the block returns a true * value. */ public static <E> int count(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.count(asList(array), block); } /** * Returns null if array has no elements; otherwise, passes the elements, * one at a time to the block. When it reaches the end, it repeats. The * number of times it repeats is set by the parameter. */ public static <E, R> Object cycle(E[] array, int times, Fn1<? super E, R> block) { return Enumerable.cycle(asList(array), times, block); } /** * Passes each entry in array to block. Returns the first for which block is * not false. If no object matches, it returns null. */ public static <E> E detect(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.detect(asList(array), block); } /** * Passes each entry in array to block. Returns the first for which block is * not false. If no object matches, it returns ifNone. */ public static <E> E detect(E[] array, Fn0<E> ifNone, Fn1<? super E, Boolean> block) { return Enumerable.detect(asList(array), ifNone, block); } /** * Calls block for each item in array. */ public static <E, R> E[] each(E[] array, Fn1<? super E, R> block) { Enumerable.each(asList(array), block); return array; } /** * Iterates the given block for each list of consecutive n elements. */ public static <E, R> Object eachCons(E[] array, int n, Fn1<List<E>, R> block) { return Enumerable.eachCons(asList(array), n, block); } /** * Iterates the given block for each slice of n elements. */ public static <E, R> Object eachSlice(E[] array, int n, Fn1<List<E>, R> block) { return Enumerable.eachSlice(asList(array), n, block); } /** * Calls block with two arguments, the item and its index, for each item in * array. */ public static <E, R> E[] eachWithIndex(E[] array, Fn2<? super E, Integer, R> block) { Enumerable.eachWithIndex(asList(array), block); return array; } /** * @see #toList(Object...) */ public static <E> EList<E> entries(E... array) { return Enumerable.toList(asList(array)); } /** * @see #detect(Object[], Fn1) */ public static <E> E find(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.find(asList(array), block); } /** * @see #detect(Object[], Fn0, Fn1) */ public static <E> E find(E[] array, Fn0<E> ifNone, Fn1<? super E, Boolean> block) { return Enumerable.find(asList(array), ifNone, block); } /** * @see #select(Object[], Fn1) */ public static <E> E[] findAll(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.findAll(asList(array), block).toArray(newEmptyArray(array)); } /** * Returns an array of every element in array for which pattern matches. */ public static <E> E[] grep(E[] array, Pattern pattern) { return Enumerable.grep(asList(array), pattern).toArray(newEmptyArray(array)); } /** * Returns an array of every element in array for which pattern matches. * Each matching element is passed to tje block, and its result is stored in * the output list. */ public static <E, R> Object[] grep(E[] array, Pattern pattern, Fn1<? super E, R> block) { return Enumerable.grep(asList(array), pattern, block).toArray(); } /** * @see #grep(Object[], Pattern) */ public static <E> E[] grep(E[] array, String pattern) { return Enumerable.grep(asList(array), pattern).toArray(newEmptyArray(array)); } /** * @see #grep(Object[], Pattern, Fn1) */ public static <E, R> Object[] grep(E[] array, String pattern, Fn1<? super E, R> block) { return Enumerable.grep(asList(array), pattern, block).toArray(); } /** * Partitions array by calling the block for each item and using the result * returned by the block to group the items into buckets. Returns a map * where the keys are the objects returned by the block, and the values for * a key are those items for which the block returned that object. */ public static <E, R> EMap<R, EList<E>> groupBy(E[] array, Fn1<? super E, R> block) { return Enumerable.groupBy(asList(array), block); } /** * Named parameter for detect. * * @see #detect(Object[], Fn0, Fn1) * @see #find(Object[], Fn0, Fn1) */ public static <R> Fn0<R> ifNone(R defaultValue) { return Enumerable.ifNone(defaultValue); } /** * @see #member(Object[], Object) */ public static <E> boolean include(E[] array, Object obj) { return Enumerable.include(asList(array), obj); } /** * Combines the elements of array by applying the block to an accumulator * value (memo) and each element in turn. At each step, memo is set to the * value returned by the block. This form uses the first element of the * array as a the initial value (and skips that element while iterating). */ public static <E> E inject(E[] array, Fn2<E, E, E> block) { return Enumerable.inject(asList(array), block); } /** * Combines the elements of array by applying the block to an accumulator * value (memo) and each element in turn. At each step, memo is set to the * value returned by the block. This form lets you supply an initial value * for memo. */ public static <E, R> R inject(E[] array, R initial, Fn2<R, E, R> block) { return Enumerable.inject(asList(array), initial, block); } /** * @see #collect(Object[], Fn1) */ public static <E, R> Object[] map(E[] array, Fn1<? super E, R> block) { return Enumerable.map(asList(array), block).toArray(); } /** * @see #collect(Object[], Fn1, Class) */ public static <E, R> R[] map(E[] array, Fn1<E, R> block, Class<R> type) { return collect(array, block, type); } /** * Returns the object in array with the maximum value. This form assumes all * objects implement {@link Comparable} */ public static <E extends Object & Comparable<? super E>> E max(E[] array) { return Enumerable.max(asList(array)); } /** * Returns the object in array with the maximum value. This form uses the * block to {@link Comparator#compare}. */ public static <E> E max(E[] array, Fn2<? super E, ? super E, Integer> block) { return Enumerable.max(asList(array), block); } /** * Passes each item in the array to the block. Returns the item * corresponding to the largest value returned by the block. */ public static <E, R extends Object & Comparable<? super R>> E maxBy(E[] array, Fn1<? super E, R> block) { return Enumerable.maxBy(asList(array), block); } /** * Returns true if any member of array equals obj. Equality is tested using * {@link Object#equals(Object)}. */ public static <E> boolean member(E[] array, Object obj) { return Enumerable.member(asList(array), obj); } /** * Returns the object in array with the minimum value. This form assumes all * objects implement {@link Comparable}. */ public static <E extends Object & Comparable<? super E>> E min(E[] array) { return Enumerable.min(asList(array)); } /** * Returns the object in array with the minimum value. This form uses the * block to {@link Comparator#compare}. */ public static <E> E min(E[] array, Fn2<? super E, ? super E, Integer> block) { return Enumerable.min(asList(array), block); } /** * Passes each item in the array to the block. Returns the item * corresponding to the smallest value returned by the block. */ public static <E, R extends Object & Comparable<? super R>> E minBy(E[] array, Fn1<? super E, R> block) { return Enumerable.minBy(asList(array), block); } /** * Compares the elements of array using {@link Comparable}, returning the * minimum and maximum value. */ public static <E extends Object & Comparable<? super E>> E[] minMax(E[] array) { return Enumerable.minMax(asList(array)).toArray(newEmptyArray(array)); } /** * Compares the elements of array using the given block, returning the * minimum and maximum value. */ public static <E> E[] minMax(E[] array, Fn2<? super E, ? super E, Integer> block) { return Enumerable.minMax(asList(array), block).toArray(newEmptyArray(array)); } /** * Passes each item in the array to the block. Returns the items * corresponding to the smallest and largest values returned by the block. */ public static <E, R extends Object & Comparable<? super R>> E[] minMaxBy(E[] array, Fn1<? super E, R> block) { return Enumerable.minMaxBy(asList(array), block).toArray(newEmptyArray(array)); } /** * Passes each element of the array to the given block. The method returns * true if the block never returns a value other than false or null. */ public static <E> boolean none(E[] array, Fn1<? super E, ?> block) { return Enumerable.none(asList(array), block); } /** * Passes each element of the array to the an implicit block of * {@link Fn1#identity()}. The method returns true if the block never * returns a value other than false or null. */ public static <E> boolean none(E[] array) { return Enumerable.none(asList(array)); } /** * Passes each element of the array to the given block. The method returns * true if the block returns true exactly one time. */ public static <E> boolean one(E[] array, Fn1<? super E, ?> block) { return Enumerable.one(asList(array), block); } /** * Passes each element of the array to the an implicit block of * {@link Fn1#identity()}. The method returns true if the block returns true * exactly one time. */ public static <E> boolean one(E[] array) { return Enumerable.one(asList(array)); } /** * Returns two lists, the first containing the elements of array for which * the block evaluates to true, the second containing the rest. */ @SuppressWarnings("unchecked") public static <E> E[][] partition(E[] array, Fn1<? super E, Boolean> block) { List<EList<E>> partition = Enumerable.partition(asList(array), block); E[][] result = (E[][]) Array.newInstance(array.getClass(), 2); result[0] = partition.get(0).toArray(newEmptyArray(array)); result[1] = partition.get(1).toArray(newEmptyArray(array)); return result; } /** * Constructs a range using the given start and end. The range will include * the end object. */ public static Integer[] range(int start, int end) { return Enumerable.range(start, end).toList().toArray(new Integer[0]); } /** * Constructs a range using the given start and end. If the third parameter * is false, the range will include the end object; otherwise, it will be * excluded. */ public static Integer[] range(int start, int end, boolean exclusive) { return Enumerable.range(start, end, exclusive).toList().toArray(new Integer[0]); } /** * @see #inject(Object[], Fn2) */ public static <E> E reduce(E[] array, Fn2<E, E, E> block) { return Enumerable.inject(asList(array), block); } /** * @see #inject(Object[], Object, Fn2) */ public static <E, R> R reduce(E[] array, R initial, Fn2<R, E, R> block) { return Enumerable.inject(asList(array), initial, block); } /** * Returns an array containing all elements of array for which block is * false. */ public static <E> E[] reject(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.reject(asList(array), block).toArray(newEmptyArray(array)); } /** * Invokes the block with the elements of array in reverse order. */ public static <E, R> E[] reverseEach(E[] array, Fn1<? super E, R> block) { Enumerable.each(new ReverseArrayIterable<E>(array), block); return array; } /** * Returns an array containing all elements of array for which block is not * false. */ public static <E> E[] select(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.select(asList(array), block).toArray(newEmptyArray(array)); } /** * Returns an array containing the items in array sorted, according to their * own compareTo method. */ public static <E extends Object & Comparable<? super E>> E[] sort(E[] array) { return Enumerable.sort(asList(array)).toArray(newEmptyArray(array)); } /** * Returns an array containing the items in array sorted by using the * results of the supplied block. */ public static <E> E[] sort(E[] array, Fn2<? super E, ? super E, Integer> block) { return Enumerable.sort(asList(array), block).toArray(newEmptyArray(array)); } /** * Sorts array using a set of keys generated by mapping the values in array * through the given block. */ public static <E, R extends Object & Comparable<? super R>> E[] sortBy(E[] array, Fn1<? super E, R> block) { return Enumerable.sortBy(asList(array), block).toArray(newEmptyArray(array)); } /** * Returns an array containing the first n items from array. */ public static <E> E[] take(E[] array, int n) { return Enumerable.take(asList(array), n).toArray(newEmptyArray(array)); } /** * Passes successive items to the block, adding them to the result array * until the block returns false or null. */ public static <E> E[] takeWhile(E[] array, Fn1<? super E, Boolean> block) { return Enumerable.takeWhile(asList(array), block).toArray(newEmptyArray(array)); } /** * Returns a list containing the items in array. */ public static <E> EList<E> toList(E... array) { return Enumerable.toList(asList(array)); } /** * Creates a new Set containing the elements of the given array. */ public static <E> ESet<E> toSet(E... array) { return Enumerable.toSet(asList(array)); } /** * Creates a new Set containing the elements of the given array, the * elements are preprocessed by the given block. */ public static <E, R> ESet<R> toSet(E[] array, Fn1<? super E, R> block) { return Enumerable.toSet(asList(array), block); } /** * Converts any arguments to iterators, then merges elements of collection * with corresponding elements from each argument. This generates a sequence * of collection#size n-element list, where n is one more that the count of * arguments. If the size of any argument is less than collection#size, null * values are supplied. The block is invoked for each output array. Returns * null. */ public static <E, R> Object zip(E[] array, Object[] args, Fn1<? super EList<?>, R> block) { List<Iterable<?>> lists = new ArrayList<Iterable<?>>(); for (int i = 0; i < args.length; i++) lists.add(asList(args[i])); return Enumerable.zip(asList(array), lists, block); } /** * Converts any arguments to iterators, then merges elements of array with * corresponding elements from each argument. This generates a sequence of * array#size n-element list, where n is one more that the count of * arguments. If the size of any argument is less than array#length, null * values are supplied. */ public static <E> Object[][] zip(E[] array, Object[]... args) { Iterable<?>[] lists = new Iterable<?>[args.length]; for (int i = 0; i < args.length; i++) lists[i] = asList(args[i]); List<EList<?>> zip = Enumerable.zip(asList(array), lists); Object[][] result = new Object[zip.size()][]; for (int i = 0; i < zip.size(); i++) result[i] = zip.get(i).toArray(); return result; } @SuppressWarnings("unchecked") static <T> T[] newEmptyArray(T[] array) { return (T[]) Array.newInstance(array.getClass().getComponentType(), 0); } static class ReverseArrayIterable<T> implements Iterable<T> { T[] array; ReverseArrayIterable(T... elements) { this.array = elements; } public Iterator<T> iterator() { return new Iterator<T>() { int i = array.length - 1; public boolean hasNext() { return i >= 0; } public T next() { if (i < 0) throw new NoSuchElementException(); return array[i--]; } public void remove() { throw new UnsupportedOperationException(); } }; } } }