I need help figuring out how to pass this BiFunction
BiFunction<Integer, List<Integer>, Integer> func = (a, b) -> {
int result = 0;
int temp = 0;
for(Integer ele : b) {
temp = b.get(ele);
result += temp;
}
return a + result;
};
I am using this junit test
void testFoldLeft() {
LinkedList<Integer> l = new LinkedList<>();
for(int i = 0; i < 10; i++) l.addFirst(i+1);
Integer u = fp.foldLeft(0, l, func(0,l));
}
I am attempting to pass the BiFunction func through foldLeft, which looks like this
static <U,V> V foldLeft(V e, Iterable<U>l, BiFunction<V,U,V> f){
return null;
}
What func is supposed to do is to take a list, in this case b, sum up all the elements in b then add that number to a and return the result. However, Eclipse gives me an error stating that func is undefined. I'm new to BiFunctions so I'm kind of stuck here. I would appreciate any help.
There are two issues in your code:
func(0,l) is a syntax error, just pass func variable as the BiFunction. No need for providing arguments:
Integer u = foldLeft(0, l, func);
The generics signature of foldLeft does not match the BiFunction. Given the current way it is written, Iterable<U> l makes the compiler infer U as Integer, hence the compiler expects the third argument to be a BiFunction<Integer, Integer, Integer> instead of BiFunction<Integer, List<Integer>, Integer>. To make U match the LinkedList<Integer>, declare it as follows:
static <U extends Iterable<V>, V> V foldLeft(V e, U l, BiFunction<V, U, V> f){
return null;
}
Side note: I wonder what the function code is doing:
for(Integer ele : b) {
temp = b.get(ele);
result += temp;
}
This is looping over elements of b and treating them as indices. I doubt this is what you want.
I think the mismatch is caused by an incorrect declaration of the second parameter of foldLeft. If, in your example, Integer is the Iterable's argument, then your method should be declared like this:
static <U, V> V foldLeft(V e, Iterable<V> l, BiFunction<V, U, V> f) {
return null;
}
V is the element type of the iterable, not U (which, in this case, would be equivalent to Iterable<V>).
Further, your invocation should look like this:
Integer u = foldLeft(0, l, func);
You can't invoke an expression in Java. Unless func is declared as a method in visible scope, func() will always be invalid.
Note that you can simplify your generics by getting rid of U (I don't see a specific need for the type variable for the list type here, but I may be missing some use cases):
static <V> V foldLeft(V e, Iterable<V> l, BiFunction<V, Iterable<V>, V> f) {
return null;
}
You do not show your implementation of foldLeft, but I'm sure it's going to need to iterate over the list, or at least pass it to f.apply. So I suppose you can make the function take a List<V>:
static <V> V foldLeft(V e, List<V> l, BiFunction<V, List<V>, V> f) {
return f.apply(e, l);
}
Otherwise, calling f.apply(e, l) would fail as Function<Integer, LinkedList<Integer>, Integer> and Function<Integer, Iterable<Integer>, Integer> are incompatible.
Related
Preface: This is not an actual problem that I have, it just came to my mind in a "What if... ...how would I do that?" fashion.
When I have Strings consisting of several key-value pairs (like 123=456;321=654;89=90), I can make a Map from that ({123=456, 321=654, 89=90}) pretty easily with a method like this:
public static Map<Integer, Integer> makeMap(String theString) {
String[] chunks = theString.split(";");
Map<Integer, Integer> result = new HashMap<>(chunks.length);
for (String chunk : chunks) {
String[] chunksChunks = chunk.split("=");
int key = Integer.parseInt(chunksChunks[0]);
int value = Integer.parseInt(chunksChunks[1]);
result.put(key, value);
}
return result;
}
Is there any elegant way to "widen" this method to be a generic method, accepting e.g. all (wrappers for) primitive types?
It would be possible to write...
public static <K extends Object, V extends Object> Map<K, V> makeMapGeneric(String theString) {
// ???
}
...but I have no idea how I would do the "castings" to the keys and values.
As far as I know, the primitive types do not have any common makeXYfromString(String ...) method, just explicit Integer.parseInt, Double.parseDouble and so on, and they do not have a common superclass/interface that I could restrict K and V to.
Giving the classes as argument (makeMapGeneric(String theString, Class<K> keyClass, Class<V> valueClass)) and writing something like K key = keyClass.cast(keyString);, isn't possible since you cannot cast a String to eg. an int, just parse it.
Is there any elegant solution possible?
I took a tought on it for a few minutes and i came up with this solution
public static <K, V> Map<K, V> makeMap(String input, Function<String, K> keyFunc, Function<String, V> valFunc) {
return Arrays.stream(input.split(";"))
.map(s -> s.split("="))
.collect(Collectors.toMap(s -> keyFunc.apply(s[0]), s -> valFunc.apply(s[1])));
}
You need to pass a two functions which will transform the string to the right value.
Use it like this:
Map<Integer, Integer> x = makeMap("123=456;321=654;89=90", Integer::parseInt, Integer::parseInt);
You could provide a Function to you method:
<K, V> Map<K, V> makeMapGeneric(String theString, Function<String, K> keyFn, Function<String, V> valueFn) {
String key = "123";
String value = "456";
K parsedKey = keyFn.apply(key);
V parsedValue = valueFn.apply(key);
}
Now you can call it with a Function that converts String to K (and V):
Map<Integer, Double> result =
makeMapGeneric("123=456", Integer::parseInt, Double::parseDouble);
Let's say I've got some lambda expressions as below:
Function<String, List<String>> flines = fileName -> {
//Puts all lines from file into List and returns a list
};
Function<List<String>, String> join = listOfLines -> {
//Concatenates all lines from list and returns them as String
};
Function<String, List<Integer>> collectInts = str -> {
//Returns all Integer occurences from given String
};
And I want to create a function, let's say resultType convertBy(Function<T,S>...args)
So I can combine arguments and return cerain result:
List<String> lines = fileConv.convertBy(flines) //returns list of lines
String text = fileConv.convertBy(flines, join); //returns s String from concatenated Strings
List<Integer> ints = fileConv.convertBy(flines, join, collectInts); //returns list of Integers from string
Integer sumints = fileConv.convertBy(flines, join, collectInts, sum); ////returns list of Integers from string and sums it
Is it somehow possible to do in Java?
EDIT: I CAN'T use overloading
When using generics, you need to declare the type variables involved. Since defining a method which chains calls using a variable number of generic functions (with varargs) would require a variable number of type variables, that's not possible to do.
It would not be possible, at compile time, to guarantee that each of functions given with varargs would use types so that they are compatible when chaining the calls.
You can do it, but not in a type-safe way. Any mismatch on the input/output types of the functions will result in a ClassCastException at runtime.
private static <T, U> U convertBy(T arg, Function... functions) {
Object result = arg;
for (Function f : functions) {
result = f.apply(result);
}
return (U) result;
}
#Test
public void test() {
Function<String, Integer> f1 = s -> s.length();
Function<Integer, Double> f2 = i -> i*2.0;
Double d = convertBy("test", f1, f2);
assertThat(d).isEqualTo(8.0);
}
You can, however, manually define variants of that method that does the chaining by overloading it:
private static <T, U> U convertBy(T arg, Function<T, U> func1) {
return func1.apply(arg);
}
private static <T, U, V> V convertBy(T arg, Function<T, U> func1, Function<U, V> func2) {
return func2.apply(func1.apply(arg));
}
private static <T, U, V, X> X convertBy(T arg, Function<T, U> func1, Function<U, V> func2, Function<V, X> func3) {
return func3.apply(func2.apply(func1.apply(arg)));
}
I'm trying Java 8, I want to iterate over 2 collections and call a parameter function for each pair of values.
In abstract, I want to apply a foo(tuple, i) function for each iteration
[ v1, v2, v3, v4, v5, v6 ] (first collection)
[ w1, w2, w3, w4, w5, w6 ] (second collection)
---------------------------
foo(<v1,w1>, 0)
foo(<v2,w2>, 1)
...
foo(<v6,w6>, 5)
Now what I got so far (java and pseudo code)
// Type of f?
private <S,U> void iterateSimultaneously(Collection<S> c1, Collection<U> c2, Function f) {
int i = 0
Iterator<S> it1 = c1.iterator()
Iterator<U> it2 = c2.iterator()
while(it1.hasNext() && it2.hasNext()) {
Tuple<S, U> tuple = new Tuple<>(it1.next(), it2.next())
// call somehow f(tuple, i)
i++
}
}
// ........................
// pseudo code, is this posible in Java?
iterateSimultaneously(c1, c2, (e1, e2, i) -> {
// play with those items and the i value
})
Is something like this what you're looking for?
private <S,U> void iterateSimultaneously(Collection<S> c1, Collection<U> c2, BiConsumer<Tuple<S, U>, Integer> f) {
int i = 0
Iterator<S> it1 = c1.iterator()
Iterator<U> it2 = c2.iterator()
while(it1.hasNext() && it2.hasNext()) {
Tuple<S, U> tuple = new Tuple<>(it1.next(), it2.next())
f.accept(tuple, i);
i++
}
}
iterateSimultaneously(c1, c2, (t, i) -> {
//stuff
})
What type is the function f supposed to return? If nothing, change it to a consumer instead. If you want it to accept a tuple you most clarify it like I have done here. Is this what you're looking for?
You are probably looking for a BiConsumer:
private <S,U> void iterateSimultaneously(Collection<S> c1, Collection<U> c2,
BiConsumer<Tuple<S, U>, Integer> f) {
f.accept(tuple, i);
}
and call it with:
iterateSimultaneously(c1, c2, (tuple, i) -> doSomethingWith(tuple, i));
The signature of doSomethingWith would look like:
private <S, U> void doSomethingWith(Tuple<S, U> tuple, int i) {
}
You can find an detailed implementation using Stream API of Java 8 of what you are looking for just here (the method zip()) :
https://github.com/JosePaumard/streams-utils/blob/master/src/main/java/org/paumard/streams/StreamsUtils.java#L398
Take a look at Guava's utilities for streams, particularly Streams.zip and Streams.mapWithIndex. You might use them both to achieve what you want:
Collection<Double> numbers = Arrays.asList(1.1, 2.2, 3.3, 4.4, 5.5);
Collection<String> letters = Arrays.asList("a", "b", "c", "d", "e");
Stream<Tuple<Double, String>> zipped = Streams.zip(
numbers.stream(),
letters.stream(),
Tuple::new);
Stream<String> withIndex = Streams.mapWithIndex(
zipped,
(tuple, index) -> index + ": " + tuple.u + "/" + tuple.v);
withIndex.forEach(System.out::println);
This produces the following output:
0: 1.1/a
1: 2.2/b
2: 3.3/c
3: 4.4/d
4: 5.5/e
This works by first zipping streams for c1 and c2 collections into one zipped stream of tuples and then mapping this zipped stream with a function that receives both each tuple and its corresponding index.
Note that Streams.mapWithIndex must receive a BiFunction, which means that it must return a value. If you want to consume both the tuples and the indices instead, I'm afraid you will need to create a new tuple containing the original tuple and the index:
Stream<Tuple<Tuple<Double, String>, Long>> withIndex = Streams.mapWithIndex(
zipped,
Tuple::new);
withIndex.forEach(tuple -> someMethod(tuple.u, tuple.v));
Where someMethod has the following signature:
<U, V> void method(Tuple<U, V> tuple, long index)
Note 1: this example assumes the following Tuple class is used:
public class Tuple<U, V> {
private final U u;
private final V v;
Tuple(U u, V v) {
this.u = u;
this.v = v;
}
// TODO: getters and setters, hashCode and equals
}
Note 2: while you can achieve the same with iterators, the main advantage of these utilities is that they also work efficiently on parallel streams.
Note 3: this functionality is available since Guava 21.0.
This question already has answers here:
Can't cast to to unspecific nested type with generics
(5 answers)
Closed 6 years ago.
I have a method with the following signature:
public <T> int numberOfValues(Map<T, Set<?>> map)
However I can’t call it passing in a Map<String, Set<String>>. For instance, the following doesn’t compile:
Map<String, Set<String>> map = new HashMap<>();
numberOfValues(map);
The error message being that:
numberOfValues (java.util.Map<java.lang.String,java.util.Set<?>>) in class cannot be applied to (java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)
However, if I change to the following all is fine:
public <T, V> int numberOfValues(Map<T, Set<V>> map)
However I’m not at all interested in V, as I just want to know the size of each of the sets.
For completeness sake, this is the whole method:
public <T, V> int numberOfValues(Map<T, Set<V>> map) {
int n = 0;
for (T key : map.keySet()) {
n += map.get(key).size();
}
return n;
}
Which I’m aware it can also be accomplished like this, but isn’t the point of the question :)
public <T> int numberOfValues(Map<?, Set<T>> map) {
int n = 0;
for (Set<T> value : map.values()) {
n += value.size();
}
return n;
}
Update: yet another way of achieving the same
public <T> int numberOfValues(Map<?, Set<T>> map) {
int n = 0;
for (Object key : map.keySet()) {
n += map.get(key).size();
}
return n;
}
Final update:
Thanks to Jorn’s answer, this is the final implementation...
public int numberOfValues(Map<?, ? extends Set<?>> map) {
int n = 0;
for (Set<?> value : map.values()) {
n += value.size();
}
return n;
}
You're missing the fact that Set<?> is also used as a generic parameter. And generics are invariant. i.e. when the parameter is Map<String, Set<?>>, the passed argument must be exactly Map<String, Set<?> (or a subtype of). Whereas with Set<V> the type argument is inferred.
You can solve this by using a bounded wildcard:
public <T> int numberOfValues(Map<T, ? extends Set<?>> map) {
...
}
Hint:
In your numberOfValues method, it is completely legal to write something like
Set<Object> set = new HashSet<>();
set.add(1);
set.add("Powned");
map.put(null, set);
You can replace the null with a suitable key already in the map to make a valid mapping, utterly breaking the type safety in the surrounding code.
Either infer or explicitly define the type of the set, or add a wildcard bound preventing mutating map access (like ? extends Set<?>)
For a Java project I'm working on, I need to make a sort-by method, which sorts a list using a mapping function. The most obvious solution is to use the built-in Collections.sort() method:
static <D, R extends Comparable> void sortBy(List<D> list, Function<D, R> function) {
Collections.sort(list, new Comparator<D>() {
#Override
public int compare(D d1, D d2) {
return function.apply(d1).compareTo(function.apply(d2));
}
});
}
The problem is that this calls the function on each element many times (I think about 2 log N). Furthermore, the function is likely to be slow, with each invocation taking at least a few milliseconds, possibly much longer. I'd like a more efficient algorithm which calls the function as few times as possible.
I've considered applying each function at the beginning, and then sorting the mapped list, but I don't see how to get back to the original list:
static <D, R extends Comparable> void sortBy(List<D> list, Function<D, R> function) {
List<R> newList = new ArrayList<>();
for (D d : list){
newList.add(function.apply(d));
}
Collections.sort(newList);
// now what?
}
(Note that the function is pure, i.e. each input yields the same output, with no side effects.)
As proposed in comments, you can sort a list of some kind of tuple that will hold the original value and the computed one. Then you build a new list by extracting the original values in sorted order.
This solution creates temporary objects (the tuples), but should be efficient if the mapping function is expensive. Of course, this needs to be measured...
static <D, R extends Comparable> List<D> sortBy(List<D> list, Function<D, R> function) {
// Build the list of pairs
List<Pair<D,R>> newList = list.stream()
.map(d -> new Pair<>(d, function.apply(d)))
.collect(Collectors.toList());
// Sort the list of pairs on second member, which is the computed one
Collections.sort(newList, new Comparator<Pair<D,R>>() {
#Override
public int compare(Pair<D, R> p1, Pair<D, R> p2) {
return p1.second.compareTo(p2.second);
}
});
// extract the first member of pair, which is the original value
return newList.stream().map(p -> p.first).collect(Collectors.toList());
}
Given a simple class Pair<U, V> like:
public final class Pair<U,V> {
public final U first;
public final V second;
public Pair(U u, V v) {
this.first = u;
this.second = v;
}
public String toString() {
return "["+first+","+second+"]";
}
}
Then:
List<String> data = Arrays.asList("blah", "foo", "bar", "hello world", "bye bye", "fizz", "buzz");
List<String> sortedDataByLength = sortBy(data, new Function<String, Integer>() {
#Override
public Integer apply(String t) {
return t.length();
}});
System.out.println(sortedDataByLength);
Yields:
[foo, bar, blah, fizz, buzz, bye bye, hello world]
Instead of R simply containing the result, implement it so that it is a composite object that contains a reference to its corresponding D as well. Then you can sort by R and extract D out of each R element in the sorted list.
You can implement simple memoization using the new Java 8 Map#computeIfAbsent(...) method:
static <D, R extends Comparable<? super R>> void sortBy(List<D> list, Function<D, R> function) {
Map<D, R> memo = new HashMap<>();
Collections.sort(list, new Comparator<D>() {
#Override
public int compare(D d1, D d2) {
R r1 = memo.computeIfAbsent(d1, function);
R r2 = memo.computeIfAbsent(d2, function);
return r1.compareTo(r2);
}
});
}