Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write generic method that receives a list and two BiFunction and evaluates expression?

I want to write a generic method that receives a List l and a two BiFunction f1, f2 and returns the result of the following expression:

(a0 + a1) * (a2 + a3) *...*(a_{n-1} + an) * an.

Here a1,...,an are the elements of the given list and + denotes f1, and * denotes f2.

The logic part is pretty simple:

List<???> resF1 = new List<>(); //calculate result of f1 for each pair

for (int i = 0; i < l.size(); i += 2) {
    resF1.add(f1.apply(l.get(i), l.get(i + 1)));
}

??? ans = f2.apply(resF1.get(0), resF1.get(1)); //get initial value of ans

for (int i = 2; i < resF1.size(); i++) {
    ans = f2.apply(ans, resF1.get(i)); //successively evaluate from left to right
}

ans = f2.apply(ans, l.get(l.size() - 1)); //don't forget about the last term of expr

return ans;

The hard part is to select generic types.

Let's start form method signature

public static <F, S, T> ??? foo(List<? extends F> l, BiFunction<???, ???, ???> f1, BiFunction<???, ???, ???> f2)

Let's assume that our function will have three generic types, so the types could be as common as possible.

I guess the type of list should be <? extends F>, since we want to read values from it and ? extends is used just for that purpose.

As for BiFunction: since we are passing list elements to it, I guess the first two fields should be also ? extends F. ? extends, for the same reason as in list, but could we make it ? extends S for f1 and ? extends T for f2?

It is also seems logical that the type of result of f1 should be equal to the type of arguments of f2, since we applying it to f2 to result of f1. However, there is the last term that contains the single element and it has ? extends F, as we deduced earlier.

As for return value, I guess it should be either T or U.

So, how would you write such a method?

like image 496
False Promise Avatar asked Dec 06 '25 02:12

False Promise


1 Answers

It looks like you're overthinking this. Since the input and output type are the same, you only need one type variable (if they weren't, you'd need a third BiFunction).

In that case you can also use BinaryOperator, which is basically the equivalent of BiFunction<T, T, T>. The result is (copying your algorithm):

public static <T> T dualFold(List<T> l, BinaryOperator<T> f1, BinaryOperator<T> f2) {
    List<T> resF1 = new ArrayList<>(); //calculate result of f1 for each pair

    for (int i = 0; i < l.size(); i += 2) {
        resF1.add(f1.apply(l.get(i), l.get(i + 1)));
    }

    T ans = f2.apply(resF1.get(0), resF1.get(1)); //get initial value of ans

    for (int i = 2; i < resF1.size(); i++) {
        ans = f2.apply(ans, resF1.get(i)); //successively evaluate from left to right
    }

    ans = f2.apply(ans, l.get(l.size() - 1)); //don't forget about the last term of expr

    return ans;
}
like image 102
Jorn Vernee Avatar answered Dec 08 '25 14:12

Jorn Vernee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!