What is the easiest way to get key associated with the max value in a map?
I believe that Collections.max(someMap) will return the max Key, when you want the key that corresponds to the max value.
For completeness, here is a java-8 way of doing it
countMap.entrySet().stream().max((entry1, entry2) -> entry1.getValue() > entry2.getValue() ? 1 : -1).get().getKey();
or
Collections.max(countMap.entrySet(), (entry1, entry2) -> entry1.getValue() - entry2.getValue()).getKey();
or
Collections.max(countMap.entrySet(), Comparator.comparingInt(Map.Entry::getValue)).getKey();
Basically you'd need to iterate over the map's entry set, remembering both the "currently known maximum" and the key associated with it. (Or just the entry containing both, of course.)
For example:
Map.Entry<Foo, Bar> maxEntry = null;
for (Map.Entry<Foo, Bar> entry : map.entrySet())
{
if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0)
{
maxEntry = entry;
}
}
A simple one liner using Java-8
Key key = Collections.max(map.entrySet(), Map.Entry.comparingByValue()).getKey();
This code will print all the keys with maximum value
public class NewClass4 {
public static void main(String[] args)
{
HashMap<Integer,Integer>map=new HashMap<Integer, Integer>();
map.put(1, 50);
map.put(2, 60);
map.put(3, 30);
map.put(4, 60);
map.put(5, 60);
int maxValueInMap=(Collections.max(map.values())); // This will return max value in the HashMap
for (Entry<Integer, Integer> entry : map.entrySet()) { // Iterate through HashMap
if (entry.getValue()==maxValueInMap) {
System.out.println(entry.getKey()); // Print the key with max value
}
}
}
}
Here's how do do it directly (without an explicit extra loop) by defining the appropriate Comparator:
int keyOfMaxValue = Collections.max(
yourMap.entrySet(),
new Comparator<Entry<Double,Integer>>(){
#Override
public int compare(Entry<Integer, Integer> o1, Entry<Integer, Integer> o2) {
return o1.getValue() > o2.getValue()? 1:-1;
}
}).getKey();
1. Using Stream
public <K, V extends Comparable<V>> V maxUsingStreamAndLambda(Map<K, V> map) {
Optional<Entry<K, V>> maxEntry = map.entrySet()
.stream()
.max((Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue()
.compareTo(e2.getValue())
);
return maxEntry.get().getKey();
}
2. Using Collections.max() with a Lambda Expression
public <K, V extends Comparable<V>> V maxUsingCollectionsMaxAndLambda(Map<K, V> map) {
Entry<K, V> maxEntry = Collections.max(map.entrySet(), (Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue()
.compareTo(e2.getValue()));
return maxEntry.getKey();
}
3. Using Stream with Method Reference
public <K, V extends Comparable<V>> V maxUsingStreamAndMethodReference(Map<K, V> map) {
Optional<Entry<K, V>> maxEntry = map.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
return maxEntry.get()
.getKey();
}
4. Using Collections.max()
public <K, V extends Comparable<V>> V maxUsingCollectionsMax(Map<K, V> map) {
Entry<K, V> maxEntry = Collections.max(map.entrySet(), new Comparator<Entry<K, V>>() {
public int compare(Entry<K, V> e1, Entry<K, V> e2) {
return e1.getValue()
.compareTo(e2.getValue());
}
});
return maxEntry.getKey();
}
5. Using Simple Iteration
public <K, V extends Comparable<V>> V maxUsingIteration(Map<K, V> map) {
Map.Entry<K, V> maxEntry = null;
for (Map.Entry<K, V> entry : map.entrySet()) {
if (maxEntry == null || entry.getValue()
.compareTo(maxEntry.getValue()) > 0) {
maxEntry = entry;
}
}
return maxEntry.getKey();
}
An answer that returns an Optional since the map may have no max value if it is empty:
map.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey);
I have two methods, using this méthod to get the key with the max value:
public static Entry<String, Integer> getMaxEntry(Map<String, Integer> map){
Entry<String, Integer> maxEntry = null;
Integer max = Collections.max(map.values());
for(Entry<String, Integer> entry : map.entrySet()) {
Integer value = entry.getValue();
if(null != value && max == value) {
maxEntry = entry;
}
}
return maxEntry;
}
As an example gettin the Entry with the max value using the method:
Map.Entry<String, Integer> maxEntry = getMaxEntry(map);
Using Java 8 we can get an object containing the max value:
Object maxEntry = Collections.max(map.entrySet(), Map.Entry.comparingByValue()).getKey();
System.out.println("maxEntry = " + maxEntry);
Simple to understand.
In Below code, maxKey is the key which is holding the max value.
int maxKey = 0;
int maxValue = 0;
for(int i : birds.keySet())
{
if(birds.get(i) > maxValue)
{
maxKey = i;
maxValue = birds.get(i);
}
}
Java 8 way to get all keys with max value.
Integer max = PROVIDED_MAP.entrySet()
.stream()
.max((entry1, entry2) -> entry1.getValue() > entry2.getValue() ? 1 : -1)
.get()
.getValue();
List listOfMax = PROVIDED_MAP.entrySet()
.stream()
.filter(entry -> entry.getValue() == max)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
System.out.println(listOfMax);
Also you can parallelize it by using parallelStream() instead of stream()
given map
HashMap abc = new HashMap<>();
get all map entries with a maximum of values.
you can use any of the below methods in the filter to get respective map entries for sets of minimum or maximum values
Collections.max(abc.values())
Collections.min(abc.values())
Collections.max(abc.keys())
Collections.max(abc.keys())
abc.entrySet().stream().filter(entry -> entry.getValue() == Collections.max(abc.values()))
if only want to get the keys for the filter map
abc.entrySet()
.stream()
.filter(entry -> entry.getValue() == Collections.max(abc.values()))
.map(Map.Entry::getKey);
if you want to get the values for the filtered map
abc.entrySet()
.stream()
.filter(entry -> entry.getValue() == Collections.max(abc.values()))
.map(Map.Entry::getvalue)
if you want to get all such keys in a list:
abc.entrySet()
.stream()
.filter(entry -> entry.getValue() == Collections.max(abc.values()))
.map(Map.Entry::getKey)
.collect(Collectors.toList())
if you want to get all such values in a list:
abc.entrySet()
.stream()
.filter(entry -> entry.getValue() == Collections.max(abc.values()))
.map(Map.Entry::getvalue)
.collect(Collectors.toList())
Is this solution ok?
int[] a = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7 };
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i : a) {
Integer count = map.get(i);
map.put(i, count != null ? count + 1 : 0);
}
Integer max = Collections.max(map.keySet());
System.out.println(max);
System.out.println(map);
int maxValue = 0;
int mKey = 0;
for(Integer key: map.keySet()){
if(map.get(key) > maxValue){
maxValue = map.get(key);
mKey = key;
}
}
System.out.println("Max Value " + maxValue + " is associated with " + mKey + " key");
Majority Element/ max element in the map :
public class Main {
public static void main(String[] args) {
int[] a = {1,3,4,3,4,3,2,3,3,3,3,3};
List<Integer> list = Arrays.stream(a).boxed().collect(Collectors.toList());
Map<Integer, Long> map = list.parallelStream()
.collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
System.out.println("Map => " + map);
//{1=1, 2=1, 3=8, 4=2}
map.entrySet()
.stream()
.max(Comparator.comparing(Entry::getValue))//compare the values and get the maximum value
.map(Entry::getKey)// get the key appearing maximum number of times
.ifPresentOrElse(System.out::println,() -> new RuntimeException("no such thing"));
/*
* OUTPUT : Map => {1=1, 2=1, 3=8, 4=2}
* 3
*/
// or in this way
System.out.println(".............");
Integer maxAppearedElement = map.entrySet()
.parallelStream()
.max(Comparator.comparing(Entry::getValue))
.map(Entry::getKey)
.get();
System.out.println(maxAppearedElement);
}
}
For my project, I used a slightly modified version of Jon's and Fathah's solution. In the case of multiple entries with the same value, it returns the last entry it finds:
public static Entry<String, Integer> getMaxEntry(Map<String, Integer> map) {
Entry<String, Integer> maxEntry = null;
Integer max = Collections.max(map.values());
for(Entry<String, Integer> entry : map.entrySet()) {
Integer value = entry.getValue();
if(null != value && max == value) {
maxEntry = entry;
}
}
return maxEntry;
}
This is going to return the keys with max value in a Map<Integer, Integer>
public Set<Integer> getMaxKeys(Map<Integer, Integer> map) {
if (map.isEmpty()) {
return Collections.emptySet();
}
return map
.entrySet()
.stream()
.collect(
groupingBy(
Map.Entry::getValue, TreeMap::new, mapping(Map.Entry::getKey, toSet())
)
)
.lastEntry()
.getValue();
}
Kotlin:
val key = map.toList().groupingBy { it }.eachCount().maxByOrNull { it.value }?.key
int max = 0;
// here m is a HashMap<String, Integer>
for(Map.Entry<String,Integer> entry : m.entrySet()){
if(entry.getValue() > max){
max = entry.getValue();
}
}
you can do like that
HashMap<Integer,Integer> hm = new HashMap<Integer,Integer>();
hm.put(1,10);
hm.put(2,45);
hm.put(3,100);
Iterator<Integer> it = hm.keySet().iterator();
Integer fk = it.next();
Integer max = hm.get(fk);
while(it.hasNext()) {
Integer k = it.next();
Integer val = hm.get(k);
if (val > max){
max = val;
fk=k;
}
}
System.out.println("Max Value "+max+" is associated with "+fk+" key");
The simplest way is:
Collections.max(hmap.values());
Related
How to find most frequent element, but when there are few most frequent element return null.
I would like to find code equivalent of:
public static void main(String[] args) {
System.out.println("Should return A -> " + mostFrequent(Arrays.asList("A", "A", "B")));
System.out.println("Should null as element in list have same frequency -> "
+ mostFrequent(Arrays.asList("A", "B")));
}
private static String mostFrequent(List<String> elements) {
Map<String, Long> ordered = new TreeMap<>();
for (String e : elements) {
if (!ordered.containsKey(e)) {
ordered.put(e, 0L);
}
Long tmp = ordered.get(e);
ordered.put(e, ++tmp);
}
String mostFrequent = null;
long i = 0;
Iterator<Map.Entry<String, Long>> it = ordered.entrySet().iterator();
while (it.hasNext() && i < 2) {
Map.Entry<String, Long> pair = it.next();
if (i == 0) {
mostFrequent = pair.getKey();
} else {
if (ordered.get(mostFrequent) == ordered.get(pair.getKey())) {
return null;
}
}
i++;
}
return mostFrequent;
}
However stream version does not handle most frequent elements with the same frequency.
private static String mostFrequentStream(List<String> elements) {
return elements.stream()
.reduce(BinaryOperator.maxBy(
Comparator.comparingInt(o -> Collections.frequency(elements, o))))
.orElse(null);
}
How to modify stream above to achieve it?
using groupingBy:
String mostFrequentStream(List<String> elements) {
Map<String, Long> temp = elements.stream()
.collect(Collectors.groupingBy(a -> a, Collectors.counting()));
return new HashSet<>(temp.values()).size() < temp.size() ?
null : temp.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey).get();
}
I managed to build a concatenated Stream but it got long:
private static String mostFrequentStream3(List<String> elements) {
return elements.stream() // part 1
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream() // part 2
.collect(Collectors.groupingBy(Entry::getValue))
.entrySet().stream() // part 3
.max(Entry.comparingByKey())
.map(Entry::getValue)
.filter(v -> v.size() == 1)
.map(v -> v.get(0).getKey())
.orElse(null);
}
To "find most frequent element, but when there are few most frequent element return null"
Part 1 counts the frequency of every element.
Part 2 groups entries by frequency.
Part 3 looks up the entry with the highest frequency. If this entry does only have one element ("there are few most frequent"), then it's the one and only maximum. Otherwise null is returned.
I would never use stream for this to avoid hurting readability and performance at the same time. For the sake of fun -
private static String mostFrequentStream(List<String> elements) {
Map<String, Long> frequencyMap = elements.stream().collect(groupingBy(Function.identity(), counting()));
return frequencyMap.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(2).reduce((i, e) -> i.getValue().equals(e.getValue()) ? new AbstractMap.SimpleEntry<>(null, 0L) : i).get().getKey();
}
I have a HashMap that map character to an Integer. In order to sort it by value I wrote my comparator and I'm using TreeMap. But I am missing the value. I checked that for String "tree". My map 'chars' after for each loop looks like {r=1, t=1, e=2} and tree after putAll (two lines later) is {e=2, r=1}. What is happening to char 't'? Why is it missed? And how can I change it?
class ValueComparator implements Comparator<Character> {
private Map<Character, Integer> map;
public ValueComparator(Map<Character, Integer> map) {
this.map = map;
}
public int compare(Character a, Character b) {
return map.get(b).compareTo(map.get(a));
}
}
public String frequencySort(String s) {
if (s.length() <= 1) return s;
HashMap<Character,Integer> chars = new HashMap<Character,Integer>();
for(Character c : s.toCharArray()){
if (chars.containsKey(c)){
chars.put(c,chars.get(c)+1);
}
else {
chars.put(c,1);
}
}
TreeMap<Character,Integer> tree = new TreeMap<Character,Integer>(new ValueComparator(chars));
tree.putAll(chars);
/**
* rest of the code
**/
}
Your ValueComparator treats entries with the same count as duplicates. A simple fix is to use the key as a tie-breaker:
public int compare(Character a, Character b) {
int result = map.get(b).compareTo(map.get(a));
return result != 0 ? result : a.compareTo(b);
}
Alternatively, you can use streams to build the frequency map, sort it and store it an ordered LinkedHashMap:
Map<Character, Integer> counts = s.chars()
.mapToObj(i -> (char)i)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(c -> 1)))
.entrySet()
.stream()
.sorted(Collections.reverseOrder(Entry.comparingByValue()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> b, LinkedHashMap::new));
This question already has answers here:
Sort a Map<Key, Value> by values
(64 answers)
Closed 7 years ago.
Forgive me if it seems simple but I couldn't figure it out easily. I thought about using a loop but was wondering if anybody knows an easier way: I have:
Map<String, Integer> map = new HashMap<>();
map.put("ClubB", 1);
map.put("ClubA", 2);
map.put("ClubC", 2);
map.put("ClubD", 2);
map.put("ClubE", 3);
map.put("ClubF", 2);
map.put("ClubG", 2);
I need to get keys or values at specific index in my tests. For example I need to get the key and value at index 3 etc. The reason is that I use a comparator and sort the Map and would like to show that the value at a specific index has changed.
Thanks for any ideas.
UPDATE:
I used:
HashMap leagueTable = new HashMap();
Map<String, Integer> map = sortByValues(leagueTable);
public <K extends Comparable<K>, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) {
return k1.compareTo(k2); // <- To sort alphabetically
} else {
return compare;
}
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
I then used aloop to print out values:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println( entry.getKey() + ", " + entry.getValue() );
}
Ended up using a for loop and comparing with what I already had added to the Map:
HashMap<String, Integer> map = new HashMap<>();
map.put("ClubD", 3);
map.put("ClubB", 1);
map.put("ClubA", 2);
map.put("ClubC", 2);
map.put("ClubE", 2);
map.put("ClubF", 2);
map.put("ClubG", 2);
Map<String, Integer> mapResult = instance.sortByValues(map);
String expectedResultKey = "ClubB";
int expectedResultValue = 1;
String resultKey = "";
int resultValue = 0;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
resultKey = entry.getKey();
resultValue = entry.getValue();
}
assertSame(expectedResultKey, resultKey);
HashMap's don't have indices. They just store data in key-value pairs.
Instead of map being a Map, why don't you use a 2D array? (And give it a more appropriate name)
String[][] array = new String[3][3];
array[3] = new String[] { "ClubD" };
array[1] = new String[] { "ClubB" };
array[2] = new String[] { "ClubA", "ClubC", "ClubE", "ClubF", "ClubG" };
System.out.println(array[3][0]);
and then if you wanted to loop through that array, you would just do:
for (int a = 0; a < array.length; a++)
for (int b = 0; b < array[a].length; b++)
if (array[a][b] != null)
System.out.println("array["+a+"]["+b+"] is: "+array[a][b]);
Map<String,String> votes = new HashMap<String,String>
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
How can I retrieve the value that most a occur in the HashMap above, in this case that would be "School". I would appreciate the most efficient and clear method to approach.
A simpler solution is to just look at the values.
public static <E> E mostFrequentElement(Iterable<E> iterable) {
Map<E, Integer> freqMap = new HashMap<>();
E mostFreq = null;
int mostFreqCount = -1;
for (E e : iterable) {
Integer count = freqMap.get(e);
freqMap.put(e, count = (count == null ? 1 : count+1));
// maintain the most frequent in a single pass.
if (count > mostFreqCount) {
mostFreq = e;
mostFreqCount = count;
}
}
return mostFreq;
}
and for a Map you can do
V v = mostFrequentElement(map.values());
One solution would be:
Construct a new HashMap that has a String key and an int value.
For each value of your current HashMap:
Add the value as the key in the new HashMap and the value as 1 if it's the first time you're inserting it.
Otherwise, increment the value by one for the current key.
Now iterate on the newly created map and retrieve the key that has the maximum value.
For your current map:
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
You'll first insert School as a key, with value 1. Then you face School again, so you increment the value by 1, having a count of 2. Now you insert Work with value 1, and Party with value 1 as well.
After iterating on the map, you'll get School with the highest value. And that's what you want!
Just using the API :
Map<String,String> votes = new HashMap<String,String>();
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
Collection<String> c = votes.values();
List<String> l = new ArrayList<>(c);
Set<String> set = new HashSet<>(c);
Iterator<String> i = set.iterator();
String valueMax = "";
int max = 0;
while(i.hasNext()){
String s = i.next();
int frequence = Collections.frequency(l, s);
if(frequence > max){
max = frequence;
valueMax = s;
}
}
System.out.println(valueMax+": "+max);
Output :
School: 2
Here is the implementation of Maroun pseudocode. Try,
Map<String, String> votes = new HashMap<String, String>();
votes.put("Henk", "School");
votes.put("Elise", "School");
votes.put("Jan", "Work");
votes.put("Mert", "Party");
//Define a countMap with String as value, Integer for count
Map<String, Integer> countMap = new HashMap<>();
for (Map.Entry<String, String> entry : votes.entrySet()) {
if (countMap.containsKey(entry.getValue())) {
countMap.put(entry.getValue(), countMap.get(entry.getValue()) + 1);
} else {
countMap.put(entry.getValue(), 1);
}
}
// Got the number of maximum occuarance
Integer maxNum = Collections.max(countMap.values());
String result = "";
// Iterate to search the result.
for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
if(maxNum==entry.getValue()){
result=entry.getKey();
}
}
System.out.println(result);
I believe this will do what you want -
/**
* Get the most frequent value present in a map.
*
* #param map
* The map to search.
* #return The most frequent value in the map (or null).
*/
public static <K, V> V getMostFrequentValue(
Map<K, V> map) {
// Make sure we have an entry.
if (map != null && map.size() > 0) {
// the entryset from our input.
Set<Entry<K, V>> entries = map.entrySet();
// we need a map to hold the count.
Map<V, Integer> countMap = new HashMap<V, Integer>();
// iterate the entries.
for (Entry<K, V> entry : entries) {
// get the value.
V value = entry.getValue();
if (countMap.containsKey(value)) {
// if we've seen it before increment the previous
// value.
countMap.put(value, countMap.get(value) + 1);
} else {
// otherwise, store 1.
countMap.put(value, 1);
}
}
// A holder for the maximum.
V maxV = null;
for (Entry<V, Integer> count : countMap.entrySet()) {
if (maxV == null) {
maxV = count.getKey();
continue;
}
if (count.getValue() > countMap.get(maxV)) {
maxV = count.getKey();
}
}
return maxV;
}
return null;
}
You could override the put() and remove() of the HashMap class and create your custom one that also controls for the number of objects added. Like so:
public class MyHashMap<K, V> extends HashMap<K, V> {
private HashMap<String, Integer> countMap = new HashMap<String, Integer>();
#Override
public V put(K key, V value) {
Integer count = countMap.get(value);
if (count != null) {
countMap.put((String) value, ++count);
} else {
countMap.put((String) value, new Integer(1));
}
return super.put(key, value);
}
#Override
public V remove(Object key) {
String countKey = (String) get(key);
Integer count = countMap.get(countKey);
if (count != null) {
countMap.put(countKey, --count);
}
return super.remove(key);
}
public Integer getCount(Object value) {
return countMap.get((String)value);
}
}
This way you don't have to loop over the elements of your HashMap to count them. Instead, after you add them:
Map<String,String> votes = new MyHashMap<String,String>
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
You could just get the count for each as:
Integer schoolCount = votes.getCount("School");
I am having some problem with sorting HashMaps with values in Java.
My code is:
#SuppressWarnings("unchecked")
Map<String, Integer> scores = ((HashMap<String, Integer>) prefs.get());
Map<String, Integer> sortedscores = sortByValues(scores);
printMap(scores);
System.out.println("==============");
printMap(sortedscores);
the prefs.get() returns a Map<String, ?> which I convert to <String, Integer >
The sorting function:
public static <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return compare;
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return new LinkedHashMap<K,V>(sortedByValues);
}
public static void printMap(Map<String, Integer> unsortMap){
for (Map.Entry entry : unsortMap.entrySet()) {
System.out.println("Key : " + entry.getKey()
+ " Value : " + entry.getValue());
}
}
The output is:
Key : John Doe Value : 1000
Key : balazs Value : 975
Key : Balazs Value : 900
Key : aladar Value : 975
Key : balazs2 Value : 975
Key : score Value : 1000
Key : house Value : 1037
==============
Key : balazs Value : 975
Key : aladar Value : 975
Key : balazs2 Value : 975
Key : Balazs Value : 900
Key : house Value : 1037
Key : John Doe Value : 1000
Key : score Value : 1000
The first one is the unsorted, the second is sorted.
My problem is that the second output is not in DESC order (by value)
EDIT:
If I create a hasmap myself it works fine:
Map<String, Integer> unsortMap = new HashMap<String, Integer>();
unsortMap.put("asd", 1);
unsortMap.put("asd2r1", 5);
unsortMap.put("house", 7);
unsortMap.put("3", 124);
unsortMap.put("7", 4);
unsortMap.put("5", 6);
unsortMap.put("6", 2);
unsortMap.put("8", 0);
But if I try it with this: Map<String, Integer> scores = ((HashMap<String, Integer>) prefs.get()); I get that wierd order.
You comparator doesn't look like it conforms to the specification:
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return compare;
Why do you return 1 when two entries are equal ?
You should basically rewrite this:
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return compare;
}
to:
public int compare(K k1, K k2) {
return map.get(k2).compareTo(map.get(k1));
}
When two values are equal, you're actually saying that one is greater than the other... which doesn't make much sense. If the keys are comparable, use the natural comparison.
I think the problem is in the return sentence:
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return new LinkedHashMap<K,V>(sortedByValues);
You have a sorted map, and then you put all the pairs in a new map, so they get unsorted again. Try to do this:
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
Found the solution:
The problem was that it was comparing Strings not integers. The conversion I tried with
Map<String, Integer> scores = ((HashMap<String, Integer>) prefs.get());
did not convert it to integer.
So I used a cycle that does it right:
for (#SuppressWarnings("rawtypes") Map.Entry entry : scores.entrySet()) {
scoresInt.put(entry.getKey().toString(), Integer.parseInt(entry.getValue().toString()));
}
With the hasmap being converted to the sorting worked like a charm.