Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8: Find index of minimum value from a List

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.

like image 352
Mubin Avatar asked Jun 29 '15 12:06

Mubin


People also ask

How do you get the index of an element in a list in Java?

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.

How do you find the minimum index?

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.


2 Answers

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
like image 194
Misha Avatar answered Sep 19 '22 20:09

Misha


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)

like image 20
Alexis C. Avatar answered Sep 20 '22 20:09

Alexis C.