1

So I'm trying to sort a HashMap that contains the person's name (key) and their age and height in cm. The HashMap is set up like this:

    Map<String, List<Integer>> s = new HashMap<>();
    List<Integer> l1, l2, l3, l4;
    l1 = new ArrayList<>();
    l2 = new ArrayList();
    l3 = new ArrayList();
    l4 = new ArrayList();
    l1.add(22); l1.add(177);  //age then height
    l2.add(45); l2.add(162);
    l3.add(19); l3.add(182);
    l4.add(38); l4.add(174); 
    s.put("John", l1);
    s.put("Eric", l2);
    s.put("Darren", l3);
    s.put("Carter", l4);

Then I want to sort the Map by the person's height using a generic function.

This is what I tried:

static <K, V extends List<? extends Comparable<? super V>>> Map<K, V> specialSort(Map<K, V> map) {
    Map<K, V> result = new LinkedHashMap<>();
    Stream<Entry<K, V>> st = map.entrySet().stream();
    st.sorted(Comparator.comparing(e -> e.getValue().get(0))).
            forEach(e -> result.put(e.getKey(), e.getValue()));

    return result;
}

However I get this error:

incompatible types: inferred type does not conform to upper bound(s)
inferred: CAP#1
upper bound(s): Comparable<? super CAP#1>,V,Object
where V,K are type-variables:
V extends List<? extends Comparable<? super V>> declared in method <K,V>specialSort(Map<K,V>)
K extends Object declared in method <K,V>specialSort(Map<K,V>)
where CAP#1 is a fresh type-variable:
CAP#1 extends Comparable<? super V> from capture of ? extends Comparable<? super V>

The base function I'm using is from this thread: https://stackoverflow.com/a/2581754

This is the function:

public static <K, V extends Comparable<? super V>> Map<K, V> 
sortByValue( Map<K, V> map )
{
   Map<K,V> result = new LinkedHashMap<>();
   Stream <Entry<K,V>> st = map.entrySet().stream();

   st.sorted(Comparator.comparing(e -> e.getValue()))
        .forEach(e ->result.put(e.getKey(),e.getValue()));

   return result;
}

I've been trying to get this to work for about an hour and a half now and I've almost given up. Please help!

Community
  • 1
  • 1
Bus
  • 11
  • 1
  • I see this line and think that it would be a lot easier to have an object with height and age fields: l1.add(22); l1.add(177); //age then height – superbAfterSemperPhi Dec 04 '14 at 23:06
  • 2
    Do you really HAVE TO put age and height into a plain ArrayList? This is not quite object-oriented. – fjf2002 Dec 04 '14 at 23:06
  • So my first question is Why do you need to sort by height? Like are you trying to do a print statement for height max to in or what is the end case. There may bater way then having to sort the list – Jay Dec 04 '14 at 23:06
  • 2
    I forget what the name is, but this really looks like the "Object Avoidance" antipattern, or something like that. Why don't you have a `Person` class with name, age, and height, and a `List` that you can sort by height. You can have a separate `Map` if you really need to look them up by name. You can fix your type errors, but I think your approach is misguided. – David Conrad Dec 04 '14 at 23:13
  • I'm mainly using this as a way to learn generics, maps and lambdas. I'm currently in the first semester of computer science and I've learned the basics of java's syntax but on my free time I've been trying to learn more stuff because I'm too impatient to wait for the class to get there. Usually what I do is I come up with a problem (in this case sorting the map by person's height) to solve. When I run into a problem I try to find an example and learn from it, but I couldn't quite find what I was looking for here, which is why I made this. I probably should have made a Person OOP class, though. – Bus Dec 05 '14 at 00:04

1 Answers1

0

Ok, like mentioned in the comments to your question, it is not really an object oriented approach
But it's fine for practicing with generics and lambdas.

It will work, when you also declare the List-type.

public static <K, V extends Comparable<? super V>> Map<K, List<V>> sortByValue( Map<K, List<V>> map ) {
   Map<K,List<V>> result = new LinkedHashMap<>();
   Stream <Entry<K,List<V>>> st = map.entrySet().stream();

   st.sorted(Comparator.comparing(e -> e.getValue().get(1)))
     .forEach(e -> result.put(e.getKey(), e.getValue()));

   return result;
}    

Alternatively, you can use the sorted method in this way:

st.sorted((e1,e2)->{return e1.getValue().get(1).compareTo(e2.getValue().get(1));})
  .forEach(e -> result.put(e.getKey(), e.getValue()));

And check the results with:

result.forEach( (name, list)-> System.out.println(""+name+":" + list.get(1).toString()));
Gren
  • 1,850
  • 1
  • 11
  • 16