/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.functions;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import xxl.core.cursors.Cursors;
import xxl.core.cursors.mappers.Mapper;
import xxl.core.functions.Functional.BinaryFunction;
import xxl.core.functions.Functional.NullaryFunction;
import xxl.core.functions.Functional.UnaryFunction;
import xxl.core.math.functions.AggregationFunction;
/**
* This class contains some useful static methods for manipulating objects of
* type {@link xxl.core.functions.Function Function}.
*/
public class Functions {
/**
* The default constructor has private access in order to ensure
* non-instantiability.
*/
private Functions() {
// private access in order to ensure non-instantiability
}
/**
* This method declares a new function <tt>h</tt> by composing a given
* function <tt>g</tt> with a function <tt>f</tt>.
*
* <p><b>Note</b> that the method does not execute the code of the new
* function <tt>h</tt>. The invocation of the composed function <tt>h</tt>
* is just triggered by a call of its own <tt>invoke-method</tt>. Then, the
* input parameters are passed to each given function <tt>f</tt>,
* and the returned objects are used as the input parameters of the
* function <tt>g</tt>. The invoke method of <tt>h</tt> returns the final
* result.</p>
*
* @param <P> the return type of the <it>inner</it> function and the type
* of the <it>outer</it> function's parameters.
* @param <R> the return type of the <it>outer</it> function, i.e., the
* return type of the composed function.
* @param <T> the type of the <it>inner</it> function's parameters, i.e.,
* the type of the composed function's parameters.
* @param g the <it>outer</it> function to be composed.
* @param f the <it>inner</it> function to be composed.
* @return the result of the composition.
*/
@SuppressWarnings("serial")
public static <P, R, T> Function<T, R> composeMulti(final Function<P, R> g, final Function<? super T, ? extends List<? extends P>> f) {
return new AbstractFunction<T, R>() {
@Override
public R invoke(List<? extends T> objects) {
return g.invoke(f.invoke(objects));
}
};
}
/**
* This method declares a new function <tt>h</tt> by composing a given
* function <tt>g</tt> with a number of functions <tt>f_1,...,f_n</tt>.
*
* <p><b>Note</b> that the method does not execute the code of the new
* function <tt>h</tt>. The invocation of the composed function <tt>h</tt>
* is just triggered by a call of its own <tt>invoke-method</tt>. Then, the
* input parameters are passed to each given function <tt>f_1,...,f_n</tt>,
* and the returned objects are used as the input parameters of the new
* function <tt>g</tt>. The invoke method of <tt>h</tt> returns the final
* result.</p>
*
* @param <P> the return type of the <it>inner</it> functions and the type
* of the <it>outer</it> function's parameters.
* @param <R> the return type of the <it>outer</it> function, i.e., the
* return type of the composed function.
* @param <T> the type of the <it>inner</it> functions' parameters, i.e.,
* the type of the composed function's parameters.
* @param g the <it>outer</it> function to be composed.
* @param f the <it>inner</it> functions to be composed.
* @return the result of the composition.
*/
public static <P, R, T> Function<T, R> compose(Function<P, R> g, Function<? super T, ? extends P>... f) {
return composeMulti(g, new DecoratorArrayFunction<T, P>(f));
}
/**
* Returns the first function value (function takes m arguments).
*
* @param <P> the type of the given function's parameters.
* @param <R> the return type of the given function.
* @param iterators iterators holding the arguments to the function. The
* number of iterators should correspond to the number of arguments
* of the function.
* @param function the function to invoke.
* @throws NoSuchElementException if the given
* {@link java.util.Iterator iterators} do not deliver the
* necessary number of objects.
* @return the first function value.
*/
public static <P, R> R returnFirst(Function<? super P, ? extends R> function, Iterator<? extends P>... iterators) throws NoSuchElementException {
return returnNth(0, function, iterators);
}
//////////////////////////////////////////////////////////////////////////////////
/**
* Returns the last function value (function takes m arguments).
*
* @param <P> the type of the given function's parameters.
* @param <R> the return type of the given function.
* @param iterators iterators holding the arguments to the function. The
* number of iterators should correspond to the number of arguments
* of the function.
* @param function the function to invoke.
* @throws NoSuchElementException if the given
* {@link java.util.Iterator iterators} do not deliver the
* necessary number of objects.
* @return the last function value.
*/
public static <P, R> R returnLast(Function<? super P, ? extends R> function, Iterator<? extends P>... iterators) throws NoSuchElementException {
return Cursors.last(new Mapper<P, R>(function, iterators));
}
//////////////////////////////////////////////////////////////////////////////////
/**
* Returns the n-th function value (function takes m arguments).
*
* @param <P> the type of the given function's parameters.
* @param <R> the return type of the given function.
* @param n the number of the returned value.
* @param iterators iterators holding the arguments to the function. The
* number of iterators should correspond to the number of arguments
* of the function.
* @param function the function to invoke.
* @throws NoSuchElementException if the given
* {@link java.util.Iterator iterators} do not deliver the
* necessary number of objects.
* @return the n-th function value.
*/
public static <P, R> R returnNth(int n, Function<? super P, ? extends R> function, Iterator<? extends P>... iterators) throws NoSuchElementException {
return Cursors.nth(new Mapper<P, R>(function, iterators), n);
}
//////////////////////////////////////////////////////////////////////////////////
/**
* Wraps an aggregation function to a unary function by storing the status
* of the aggregation internally.
*
* @param <P> the type of the function's parameters.
* @param <R> the return type of the function.
* @param aggregateFunction aggregation function to provide as an unary function
* @return an unary function wrapping an aggregation function
*/
@SuppressWarnings("serial")
public static <P, R> Function<P, R> aggregateUnaryFunction(final AggregationFunction<P, R> aggregateFunction) {
return new AbstractFunction<P, R>() {
R agg = null;
@Override
public R invoke(P o) {
agg = aggregateFunction.invoke(agg, o);
return agg;
}
};
}
//////////////////////////////////////////////////////////////////////////////////
/**
* Returns an one-dimensional real-valued function providing an absolute of
* a {@link java.lang.Number number}. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing an
* absolute of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> abs() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number number){
return number.doubleValue() < 0 ? -number.doubleValue() : number.doubleValue();
}
};
}
/**
* Returns an one-dimensional real-valued function providing a negative of
* a {@link java.lang.Number number}. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing a
* negation of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> minus() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number number){
return -number.doubleValue();
}
};
}
/**
* Returns an one-dimensional real-valued function providing a product of
* two {@link java.lang.Number numbers}. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing a
* multiplication of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> mult() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number multiplicand, Number multiplicator){
return multiplicand.doubleValue() * multiplicator.doubleValue();
}
};
}
/**
* Returns an one-dimensional real-valued function providing a quotient of
* two {@link java.lang.Number numbers}. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing a
* division of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> div() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number dividend, Number divisor){
return dividend.doubleValue() / divisor.doubleValue();
}
};
}
/**
* Returns an one-dimensional real-valued function providing a sum of two
* {@link java.lang.Number numbers}. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing a
* summation of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> add() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number augend, Number addend){
return augend.doubleValue() + addend.doubleValue();
}
};
}
/**
* Returns an one-dimensional real-valued function providing a difference
* of two {@link java.lang.Number numbers}. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing a
* subtraction of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> sub() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number minuend, Number subtrahend){
return minuend.doubleValue() - subtrahend.doubleValue();
}
};
}
/**
* Returns an one-dimensional real-valued function providing an
* exponentiation of two {@link java.lang.Number numbers}. The result of
* the mathematical operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} performing an
* exponentiation of numerical data.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> exp() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number base, Number exponent){
return Math.pow(base.doubleValue(), exponent.doubleValue());
}
};
}
/**
* Returns an one-dimensional real-valued function providing the
* trigonometric sine of an angle. The result of the mathematical operation
* will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} providing the
* trigonometric sine of an angle.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> sin() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number x) {
return Math.sin(x.doubleValue());
}
};
}
/**
* Returns an one-dimensional real-valued function providing the
* trigonometric cosine of an angle. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} providing the
* trigonometric cosine of an angle.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> cos() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number x) {
return Math.cos(x.doubleValue());
}
};
}
/**
* Returns an one-dimensional real-valued function providing the
* trigonometric tangent of an angle. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} providing the
* trigonometric tangent of an angle.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> tan() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(Number x) {
return Math.tan(x.doubleValue());
}
};
}
/**
* Returns an one-dimensional real-valued function providing the
* trigonometric cosine of an angle. The result of the mathematical
* operation will be returned by a double number!
*
* @return a {@link xxl.core.functions.Function Function} providing the
* trigonometric cosine of an angle.
*/
@SuppressWarnings("serial")
public static Function<Number, Double> sum() {
return new AbstractFunction<Number, Double>() {
@Override
public Double invoke(List<? extends Number> summands) {
double sum = 0;
for (Number summand : summands)
sum += summand.doubleValue();
return sum;
}
};
}
/**
* Returns a function providing a concatenation of two
* {@link java.lang.Object obejct's} string representations. The result of
* the operation will be returned by a string!
*
* @return a {@link xxl.core.functions.Function Function} performing a
* concatenation of two object's string representation.
*/
@SuppressWarnings("serial")
public static Function<Object, String> concat() {
return new AbstractFunction<Object, String>() {
@Override
public String invoke(Object firstObject, Object secondObject){
return firstObject.toString() + secondObject.toString();
}
};
}
/**
* Returns the hash-value of the given object wrapped to an Integer
* instance. Note, this implementation delivers an unary function. Do not
* apply to none, two or more parameters.
*
* @return the hash-value of the given object.
*/
@SuppressWarnings("serial")
public static Function<Object, Integer> hash() {
return new AbstractFunction<Object, Integer>() {
@Override
public Integer invoke(Object o) {
return o.hashCode();
}
};
}
/**
* This method returns a function which is the identity function with the
* side effect of sending the object to a PrintStream.
*
* @param <T> the type of the objects the returned function is able to
* process.
* @param ps PrintStream to which the object is sent.
* @return the desired function.
*/
public static <T> Function<T, T> printlnMapFunction(final PrintStream ps) {
return new Print<T>(ps, true);
}
/**
* This method returns a function which is the identity function with the
* side effect of sending the object to a PrintStream.
*
* @param <P> the type of the given function's parameters.
* @param <R> the return type of the given function.
* @param f Function to be decorated.
* @param ps PrintStream to which the object is sent.
* @param showArgs showing the arguments which are sent to the Function?
* (yes/no).
* @param beforeArgs String which is printed at first (before writing the
* arguments).
* @param argDelimiter String which delimits the arguments from each other.
* @param beforeResultDelimiter String which is places between the last
* argument (if this is printed) and the rest.
* @param afterResultDelimiter String which is printed after the result (at
* the end).
* @return the desired function
*/
@SuppressWarnings("serial")
public static <P, R> Function<P, R> printlnDecoratorFunction(final Function<? super P, ? extends R> f, final PrintStream ps, final boolean showArgs, final String beforeArgs, final String argDelimiter, final String beforeResultDelimiter, final String afterResultDelimiter) {
return new AbstractFunction<P, R>() {
@Override
public R invoke(List<? extends P> o) {
ps.print(beforeArgs);
if (showArgs) {
for (int i = 0; i < o.size()-1; i++) {
ps.print(o.get(i));
ps.print(argDelimiter);
}
ps.print(o.get(o.size()-1));
}
ps.print(beforeResultDelimiter);
R ret = f.invoke(o);
ps.print(ret);
ps.print(afterResultDelimiter);
return ret;
}
};
}
/**
* This method returns a function which is the identity function with an
* additional test. If the objects of subsequent invoke-calls do not adhere
* to the given comparator, a runtime exception is sent.
*
* @param <T> the type of the objects the returned function is able to
* process.
* @param c the comparator.
* @param ascending true iff the order is ascending, else false.
* @return the desired function.
*/
@SuppressWarnings("serial")
public static <T> Function<T, T> comparatorTestMapFunction(final Comparator<? super T> c, final boolean ascending) {
return new AbstractFunction<T, T>() {
boolean first = true;
T lastObject;
int value = ascending?+1:-1;
@Override
public T invoke(T o) {
if (first)
first = false;
else if (c.compare(lastObject,o)*value>0)
throw new RuntimeException("Ordering is not correct");
lastObject = o;
return o;
}
};
}
/**
* Makes a given function able to handle null values. The defaultValue is
* the return value of the function if one of the parameters is a null
* value. If no null value is handed over the given function is called.
*
* @param <P> the type of the functions's parameters.
* @param <R> the return type of the given function.
* @param function the given function.
* @param defaultValue the default value.
* @return the function able to handle null values.
*/
@SuppressWarnings("serial")
public static <P, R> Function<P, R> newNullSensitiveFunction(final Function<? super P, ? extends R> function, final R defaultValue) {
return new AbstractFunction<P, R>() {
@Override
public R invoke(List<? extends P> arguments) {
for (P argument : arguments)
if (argument == null)
return defaultValue;
return function.invoke(arguments);
}
};
}
/**
* Returns a function the selects to <code>index</code>th argument of its
* input parameters and returns it.
*
* @param <T> the type of the function's parameters and result.
* @param index the index of the argument to be returned.
* @return a function the selects to <code>index</code>th argument of its
* input parameters and returns it.
*/
@SuppressWarnings("serial")
public static <T> Function<T, T> select(final int index) {
return new AbstractFunction<T, T>() {
@Override
public T invoke(List<? extends T> arguments) {
if (arguments.size() <= index)
throw new IllegalArgumentException("not enough arguments");
return arguments.get(index);
}
};
}
////////////////////////////////////////////////////////////////////////////////////
// compatibility methods
///////////////////////////////////////////////////////////////////////////////////
/**
* Wrap to function object
* @param nullaryFunction
* @return
*/
public static <T> Function<Object,T> toFunction(final NullaryFunction<T> nullaryFunction){
return new AbstractFunction<Object, T>() {
public T invoke() {
return nullaryFunction.invoke();
};
};
}
/**
* Wraps old function object
* @param unaryFunction
* @return
*/
public static <I,O> Function<I,O> toFunction(final UnaryFunction<I, O> unaryFunction){
return new AbstractFunction<I, O>() {
public O invoke(I argument) {
return unaryFunction.invoke(argument);
};
};
}
/**
*
* @param binaryFunction
* @return
*/
public static <I0, I1, O> Function<Object,O> toFunction(final BinaryFunction<I0, I1, O> binaryFunction){
return new AbstractFunction<Object, O>() {
@Override
public O invoke(Object argument0, Object argument1) {
return binaryFunction.invoke((I0)argument0, (I1)argument1);
}
};
}
}