Get min and max of supplier streams - java

I know if i use:
double data[][] = new double[n][];
// fill the array
DoubleStream stream = Arrays.stream(data).flatMapToDouble(Arrays::stream);
int max = stream.max().getAsDouble();
DoubleStream stream = Arrays.stream(data).flatMapToDouble(Arrays::stream);
int min = stream.min().getAsDouble();
i will get the minimum and maximum of whatever value the stream has as a double.
However i cant for the life of me figure out how to make it into a "Supplier". since
Supplier<Stream> stream = (Supplier<Stream>) Arrays.stream(data).flatMapToDouble(Arrays::stream);
double max = stream.max().getAsDouble();
double min = stream.min().getAsDouble();
doesn not work, and Supplier<DoubleStream> does not work ether.
i managed to get it to work with
Supplier<DoubleStream> stream = () -> Arrays.stream(t).flatMapToDouble(Arrays::stream);
OptionalDouble max = stream.get().max();
OptionalDouble min = stream.get().min();
but why did the values in the stream become a OptionalDouble?

Casting a DoubleStream to a Supplier<DoubleStream> does not make a DoubleStream a Supplier<DoubleStream>.
You need a lambda expression () -> stream to form a supplier of the stream:
Supplier<DoubleStream> supplier = () -> Arrays.stream(data).flatMapToDouble(Arrays::stream);
The max value then can be determined by:
double max = supplier.get().max().orElse(Double.MIN_VALUE);
// where Double.MIN_VALUE can be any other default 'double' value if max is not present
since the max() over DoubleStream returns an OptionalDouble.

The Supplier<T> functional interface has a single abstract method:
#FunctionalInterface
public Supplier<T> {
T get();
}
As it's a functional interface, you could use a lambda expression (or a method reference) to create an instance of the Supplier type:
Supplier<Integer> supplier = () -> 1;
If you change the Integer generic type to DoubleStream, then you'd get what you want:
Supplier<DoubleStream> supplier = Arrays.stream(data).flatMapToDouble(Arrays::stream);
Casting is not magic: if you have a DoubleStream instance, you can't just cast that instance to Supplier<DoubleStream> and expect the cast to magically transform the stream to a supplier.
Despite all this, it's not clear at all why you need to get a supplier from the stream in the first place.
Regarding the return type of DoubleStream.max and DoubleStream.min methods, it's OptionalDouble (instead of just double) because the stream might be empty, in which case there would be neither a max nor a min value. In this case, the returned OptionalDouble instance would be empty.

Related

Printing max element in a Deque<Integer>

I have a Deque from Integers, which I'm using as a Que. I have to add and remove elements from it and in some cases I need to print the max value in the Que.
The thing that I've tried is:
System.out.println(deque.stream().max(Integer::compareTo));
But it prints - Optional[the current max int].
Thank you!
That is because the max method of java.util.Stream returns your value wrapped in Optional. This is the signature of the max method Optional<T> max(Comparator<? super T> comparator);
The example below would provide you the expected behaviour:
Optional<Integer> optionalOfMax = deque.stream().max(Integer::compareTo);
System.out.println(optionalOfMax.orElseThrow());
You can do it as follows:
deque.stream().max(Integer::compareTo).ifPresent(System.out::println);
Note that deque.stream().max(Integer::compareTo) returns Optional<Integer>.
Alternatively,
deque.stream().flatMapToInt(x -> IntStream.of(x)).max().ifPresent(System.out::println);
Stream#flatMapToInt returns an IntStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
You can just use the code you have written and extend it by .get().
The following code
public static void main(String[] args) {
// create a Deque that holds Integers
Deque<Integer> myDQ = new ArrayDeque<Integer>();
// add some of them
myDQ.add(12);
myDQ.add(13);
myDQ.add(14);
myDQ.add(15);
myDQ.add(16);
myDQ.add(20);
myDQ.add(17);
myDQ.add(18);
myDQ.add(19);
// and print
System.out.println(
myDQ.stream()
.max(Integer::compareTo) // the largest one
.get() // not as Optional but only as Integer
);
}
just prints 20.
The max-Method returns an java.util.Optional. If you just want to return a int-Value you can use the orElse-Method from java.util.Optional to return the given value or, if not present, another default.
System.out.println(deque.stream().max(Integer::compareTo).orElse(0));
You can unbox the Integer wrappers in your queue and use IntStream.max(), which returns an OptionalInt:
deque.stream().mapToInt(Integer::intValue)
.max()
.ifPresent(System.out::println);
This will do nothing if max() returns OptionalInt.empty(), which happens when the deque is empty. If you want to check for emptiness, you can do, for example:
deque.stream().mapToInt(Integer::intValue)
.max()
.ifPresentOrElse(System.out::println,
() -> throw new RuntimeException("Attempt to get max of empty collection"));

bad return type in lambda expression when creating a Long type maxHeap using PriorityQueue

I tried to create a Long type maxHeap using PriorityQueue.
PriorityQueue<Long> maxHeap = new PriorityQueue<Long>((a, b) -> (b - a));
But the compiler returned an error incompatible types: bad return type in lambda expression
Can someone explain:
Why is there an error?
What's the right way to do it?
Why is there an error?
It is an error because the PriorityQueue<Long> expects a Comparator<Long> and the Comparator<Long>.compare(Long, Long) method has the signature int compare(Long o1, Long o2);.
Your lambda expression however has a result type long and that doesn't match the required signature.
What's the right way to do it?
Its either using the natural order by using the no-args constructor:
PriorityQueue<Long> maxHeap = new PriorityQueue<>();
Or providing the correct Comparator by using a method reference to Long.compareTo(Long):
PriorityQueue<Long> maxHeap = new PriorityQueue<>(Long::compareTo);
On a side note: even for Integer, (a, b) -> a - b is not a valid Comparator<Integer> lambda.
A comparator must return a value greater than zero if a is greater than b, but for int a = 2_000_000_000; and int b = -2_000_000_000; the expression a-b has a result less than zero (due to integer overflow).
So even for Integer you must use Integer::compareTo (if you have two Integer values)or Integer::compare (if you have two int values).

How save a native variable with streams

Hi im trying to understand java 8 api streams, i dont know if this can be done, but im trying to do a filter to a list a save in a new variable like this and the compiler say to me that he cant convert from Stream to String and it has sense but how can i do the operation?
List<String> lista = new ArrayList<String>();
lista.add("1");
lista.add("2");
String num = lista.stream().filter(x -> x.equals("1"));
And if i want to convert that string to int i try to do this but also the compiler say to me, wrong types
List<String> lista = new ArrayList<String>();
lista.add("1");
lista.add("2");
int num = lista.stream().filter(x -> x.equals("1")).map(x -> Integer.parseInt(x));
Streams don't start processing until a terminal method is given to start it. So try this:
List<String> lista = new ArrayList<String>();
lista.add("1");
lista.add("2");
int num = lista.stream().filter(x -> x.equals("1"))
.mapToInt(Integer::parseInt) // use method reference here.
.findFirst().orElse(0);
findFirst returns an OptionalInt so you need to have a default value to return if nothing is found. orElse does that. Also use mapToInt since Integer::parseInt returns an int. Avoids unnecessary boxing. You can apply a similar technique to just get the String when you don't need to parse an int.
You are missing just one call to findFirst:
String num = lista.stream().filter(x -> x.equals("1")).findFirst().get();
And also for the Map:
int num = lista.stream().filter(x -> x.equals("1")).map(x -> Integer.parseInt(x)).findFirst().get();
Be careful when using get method of Optional, if the filter returns nothing it will throw NoSuchElementException.

How to find max length in list of string using streams in Java?

I have a class like below:
public class A
{
String name;
String getName(){return name;}
}
And I also have a list like below:
List<A> list_a = new ArrayList<>();
//add n objects into list_a
Right now I would like to find the max length of object which is in list_a using streams in Java. I have created code like below:
final int max_len = list_a.stream().max(Comparator.comparingInt(A::getName::length));
But it does not work, I mean it is something bad with syntax. Could you help me with this? Thank you.
What you are using isn't lambda. Lambda looks like (arguments) -> action. What you have in A::getName is method reference, but additional ::length is not part of its syntax.
Instead of A::getName::length you can use lambda like a -> a.getName().length().
But your code has yet another problem. Code
list_a.stream()
.max(Comparator.comparingInt(A::getName::length));
is handling streams of A and max method called on Stream<A> will result in Optional<A> not int. It is Optional because there is a chance that list_a can be empty which means that there will be no valid result.
If you want to get OptionalInt you would need to map Stream<A> to Stream<String> and then map it to Stream of ints first. Then you can call its max() method and get:
OptionalInt maxOpt = list_a.stream()
.map(A::getName)
.mapToInt(String::length)
.max();
When you already have OptionalInt you can use it to check if value there isPresent() and get it via getAsInt(). You can also use orElse(defaultValueIfEmpty) like
int max = maxOpt.orElse(-1); //will return value held by maxOpt, or -1 if there is no value
You can use an IntStream as you're just looking for the max length:
OptionalInt oi = list_a.stream()
.map(A::getName)
.mapToInt(String::length)
.max()
final int max_len = oi.orElse(0); //defaulting to 0
If you need to use a custom comparator, you will need a lambda expression:
final int max_len = list_a.stream()
.max(Comparator.comparingInt(a ->
a.getName().length())) //need a lambda
.map(A::getName)
.map(String::length)
.orElse(0); //defaulting to 0
Alternative solution using Collections.max:
A a = Collections.max(list_a, Comparator.comparing(obj -> obj.getName().length()));
int maxLen = a.getName().length();
Keep in mind that Collections.max throws NoSuchElementException if the collection is empty. If you don't want it, use the approach with OptionalInt like in #Pshemo's answer.

How to formulate an elegant vertex for Hazelcast Jet to get the minimum?

I'm trying to wrap my head aroun the bifunction usage in Hazelcast Jets accumulate processor. First attempt is a simple min comparison, but what I came up with looks so unelegant. Is there a better way to do it?
Vertex min = dag.newVertex("min", accumulate(()
-> new myObject(Type.SOME_ENUM,Double.MAX_VALUE,0L),
(cMin, x) -> (((myObject) x).getValue() < cMin.Value()) ? (myObject) x) : cMin,
(cMin) -> cMin));
Basically I have a class with 3 fields: Type, Value, TimeStamp, and I want to get object with the lowest value.
My supplier is a new object with value at max.double, which looks fine. My finisher just hands through the object which is fine as well.
But the accumulator looks unneccesarily complicated. Is there a way to avoid having to cast x to myObject twice? Or some even more elegant way, to just keep the double value, but still return the object at the end? WITHOUT having to iterate to the whole map to get the object for the min value again?
There is nothing in your expression that indicates the type of the item the accumulator function expects (the x). Theoretically it could be inferred by propagating the known type of the accumulated value into the expression which constitutes lambda body and finding out that x must be assignment-compatible with it, but Java does not do that.
So you must add more explicit typing, for example by providing explicit types in the accumulator function:
Vertex min = dag.newVertex("min", accumulate(() -> new MyObject(Double.MAX_VALUE),
(MyObject acc, MyObject x) -> x.getValue() < acc.getValue() ? x : acc));
You can use type parameters to static method:
Vertex min = dag.newVertex("min", Processors.<myObject, myObject>accumulate(
() -> new myObject(Type.SOME_ENUM,Double.MAX_VALUE,0L),
(cMin, x) -> x.getValue() < cMin.getValue() ? x : cMin));
I also used the two-parameter constructor, which provides identity() as the third argument.
Btw, myObject should be MyObject, this is a Java convention.

Categories

Resources