4

I am looking to get minimum value from a list of maps in java. I am using combination of flatmap,stream and min to do so and not getting expected results. Here is the code public class TestMin {

public  static class TestHolder{
    public  static Map<String,Integer> getValues(){
        Map<String,Integer> map = new HashMap<>();
        map.put("a",1);
        map.put("b",3);
        map.put("c",2);

        return map;

    }
}

public static void main(String[] args) {
    List<Map<String, Integer>> l = new ArrayList<>();
    l.add(TestHolder.getValues());
    l.add(TestHolder.getValues());
    l.add(TestHolder.getValues());

    // Getting min
    int min = l.stream().map((m)->m.values()).flatMap((v)->v.stream()).min(Integer::min).get();
    System.out.println(min);
    }

}

Output is: 2

Of course, the output that I am expecting is 1. Trying some debugging suggests that it is providing an output a value corresponding to "c". i.e if map looks like

[a->2 , b->3, c->1] 

Then the output I am getting is 1. The question is why it is not sorting by values and rather sorting by keys and providing me the unexpected output.

maneet
  • 295
  • 2
  • 10

2 Answers2

6

Stream::min expects something that adheres to the Comparator contract. But Integer::min doesn't do that, it just returns the minimum of its two inputs. You should be using Integer::compare instead.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Thanks, Oliver@ for the reply. As expected, you are right. A follow up question how can we catch such errors/bugs at compile time? – maneet Apr 12 '17 at 19:42
  • @maneet You can't, but you can write tests. – Flown Apr 12 '17 at 19:43
  • 1
    @maneet - This is a logic bug; it's not clear how one would be able to catch that at compile time (given that `Comparator::compareTo` returns an `int`). – Oliver Charlesworth Apr 12 '17 at 19:43
  • Flown@ You are right. Actually, that is how I caught this. Thanks Oliver@ for the reply :-) – maneet Apr 12 '17 at 19:44
0

You could use mapToInt() function to convert Stream<Integer> to IntStream and then just call min() on it:

int min = l.stream()
        .map(Map::values)
        .flatMap(Collection::stream)
        .mapToInt(Integer::intValue)
        .min().orElse(defaultMinValue);
Pavlo Viazovskyy
  • 927
  • 5
  • 12