Computing multiple results from one array iteration
I want to compute multiple functions in one iteration of an array or list, but might want to grow the list of functions dynamically. For example, I might want to compute min and max, and then, also want the average function (or any other linear complexity function) sometime later. So, I might want to have a high-level specification (using some functions called addFunc
and applyAllFuncs
such as
funcs = empty开发者_运维问答FunctionList; # no functions in funcs "list" yet
funcs = addFunc (min, funcs); # add minimum function
funcs1 = addFunc (max, funcs); # add maximum function
answers1 = applyAllFuncs (funcs1, myArray);
funcs2 = addFunc (avg, funcs); # add average function
answers2 = applyAllFuncs (funcs2, myArray);
I can do this quite easily in a functional language by creating a "superfunction" from these functions that gets passed to a foldl
, and metaprogramming might be a mechanism to also do this much more efficiently in Haskell/C++, but wanted to know if there's an efficient and not-very-complex way that this is normally done (or can be done) in standard Java (without having to do a lot to simulate/implement higher-level functions).
Here is the complete working Java code equivalent to the functional pseudocode you have given in your post:
import java.util.*;
interface Function1<A, B> {
public B apply(final A a);
}
class Main {
public static <A, B> List<Function1<A, B>> addFunc(final Function1<A, B> f, final List<Function1<A, B>> fs) {
final List<Function1<A, B>> gs = new ArrayList<Function1<A, B>>();
gs.addAll(fs);
gs.add(f);
return gs;
}
public static <A, B> List<B> applyAllFuncs(final List<Function1<List<A>, B>> fs, final List<A> as) {
final List<B> bs = new ArrayList<B>();
for(final Function1<List<A>, B> f : fs) {
bs.add(f.apply(as));
}
return bs;
}
public static Function1<List<Double>, Double> min = new Function1<List<Double>, Double>() {
public Double apply(final List<Double> xs) {
double mx = xs.get(0);
for(final Double x : xs) {
if(x < mx) {
mx = x;
}
}
return mx;
}
};
public static Function1<List<Double>, Double> avg = new Function1<List<Double>, Double>() {
public Double apply(final List<Double> xs) {
double sum = 0;
for(final Double x : xs) {
sum += x;
}
return sum / xs.size();
}
};
public static Function1<List<Double>, Double> max = new Function1<List<Double>, Double>() {
public Double apply(final List<Double> xs) {
double mx = xs.get(0);
for(final Double x : xs) {
if(x > mx) {
mx = x;
}
}
return mx;
}
};
public static void main(final String[] args) {
final List<Double> myArray = Arrays.asList(3.0, 8, 1, 2, 9);
List<Function1<List<Double>, Double>> funcs = new ArrayList<Function1<List<Double>, Double>>();
funcs = addFunc(min, funcs);
final List<Function1<List<Double>, Double>> funcs1 = addFunc(max, funcs);
final List<Double> answers = applyAllFuncs(funcs1, myArray);
final List<Function1<List<Double>, Double>> funcs2 = addFunc(avg, funcs);
final List<Double> answers2 = applyAllFuncs(funcs2, myArray);
System.out.println(answers + "\n" + answers2);
}
}
Much of this boilerplate could be avoided if you use already existing functional programming libraries for Java, such as Functional Java or the one offered by GridGain.
Not much of this gets optimized away, as JVM was never intended for this sort of stuff. Scala, which is a functional language on JVM, uses the same methods as above for the implementation of lambdas and higher order functions, and gives on par performance with Java. Still I advise that you should profile the code and decide if it satisfies the performance requirements of your particular use case.
Create your own fold:
Have a method that takes in a list and a list of functions to run on the list.
The list of functions to run on the list could simply be an ArrayList<XFunction>
where XFunction
is a class you define that has a method (say run(...)
) and you can create an anonymous implementation of it for each function.
Ex:
list.add(new XFunction(){
run(ArrayList<int> numbers){
return numbers.size();
}
}
Which of course is not a function that solves anything, but you get the idea
You can use some kind of Stategy pattern :
public interface Function{
public void Compute();
}
public Function1 implements Function{
public void Compute(){
System.out.println("This is Function1");
}
}
public Function2 implements Function{
public void Compute(){
System.out.println("This is Function2");
}
}
After that declare a container of Function:
ArrayList<Function> functions = new ArrayList<Function>();
functions.add(new Function1());
functions.add(new Function2());
ArrayList<Object> someData = new ArrayList<Object>();
Something.execute(someData,functions);
精彩评论