Say I have a list with elements (34, 11, 98, 56, 43)
.
Using Java 8 streams, how do I find the index of the minimum element of the list (e.g. 1 in this case)?
I know this can be done easily in Java using list.indexOf(Collections.min(list))
. However, I am looking at a Scala like solution where we can simply say List(34, 11, 98, 56, 43).zipWithIndex.min._2
to get the index of minimum value.
Is there anything that can be done using streams or lambda expressions (say Java 8 specific features) to achieve the same result.
Note: This is just for learning purpose. I don't have any problem in using Collections
utility methods.
indexOf() in Java. The indexOf() method of ArrayList returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. Syntax : public int IndexOf(Object o) obj : The element to search for.
Python's inbuilt function allows us to find it in one line, we can find the minimum in the list using the min() function and then use the index() function to find out the index of that minimum element.
import static java.util.Comparator.comparingInt;
int minIndex = IntStream.range(0,list.size()).boxed()
.min(comparingInt(list::get))
.get(); // or throw if empty list
As @TagirValeev mentions in his answer, you can avoid boxing by using IntStream#reduce
instead of Stream#min
, but at the cost of obscuring the intent:
int minIdx = IntStream.range(0,list.size())
.reduce((i,j) -> list.get(i) > list.get(j) ? j : i)
.getAsInt(); // or throw
You could do it like this:
int indexMin = IntStream.range(0, list.size())
.mapToObj(i -> new SimpleEntry<>(i, list.get(i)))
.min(comparingInt(SimpleEntry::getValue))
.map(SimpleEntry::getKey)
.orElse(-1);
If the list is a random access list, get
is a constant time operation. The API lacks of a standard tuple class, so I used the SimpleEntry
from the AbstractMap
class as a substitute.
So IntStream.range
generates a stream of indexes from the list from which you map each index to its corresponding value. Then you get the minimum element by providing a comparator on the values (the ones in the list). From there you map the Optional<SimpleEntry<Integer, Integer>>
to an Optional<Integer>
from which you get the index (or -1 if the optional is empty).
As an aside, I would probably use a simple for-loop to get the index of the minimum value, as your combination of min
/ indexOf
does 2 passes over the list.
You might also be interested to check Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With