How to sort a treemap based on its values?
Asked Answered
C

9

16

How can I sort a treemap using its values rather than the key?

Clements answered 19/9, 2009 at 11:24 Comment(1)
The first solution in this link is the best you can have. https://mcmap.net/q/47071/-treemap-sort-by-valueImpotence
V
17

You cannot as the TreeMap's comparator is run against the keys only, e.g. see this constructor.

Anyway, you can use multiple Collections, use the TreeMap (or rather HashMap) for looking up elements by keys, and have a SortedSet to iterate on the values.

Vorlage answered 19/9, 2009 at 11:35 Comment(0)
Z
25

Here is a solution:

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 sortedByValues;
}

Note that the map is sorted from the highest value to the lowest.

Zachary answered 21/1, 2010 at 20:49 Comment(2)
I'm getting a stackoverflow exception with this methodYuji
this is actually not working! unless all the data is in the original Map<K,V> map and you never need to put new valuesMcnulty
V
17

You cannot as the TreeMap's comparator is run against the keys only, e.g. see this constructor.

Anyway, you can use multiple Collections, use the TreeMap (or rather HashMap) for looking up elements by keys, and have a SortedSet to iterate on the values.

Vorlage answered 19/9, 2009 at 11:35 Comment(0)
N
6

Google Guava provides a TreeMultiMap.

You could also use two collections. What are you trying to accomplish? Can you explain your use cases?

Numbers answered 19/9, 2009 at 12:5 Comment(0)
M
5

Apache Commons Collections has a TreeBidiMap:

This class guarantees that the map will be in both ascending key order and ascending value order, sorted according to the natural order for the key's and value's classes.

There's a Java5-generics port of it here.

Mutinous answered 19/9, 2009 at 11:31 Comment(0)
E
4

Try below code it works fine for me. You can choose both ascending as well as descending order for sorting.

package com.rais;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class SortMapByValue
{
    public static boolean ASC = true;
    public static boolean DESC = false;

    public static void main(String[] args)
    {

        // Creating dummy unsorted map
        Map<String, Integer> unsortMap = new HashMap<String, Integer>();
        unsortMap.put("B", 55);
        unsortMap.put("A", 80);
        unsortMap.put("D", 20);
        unsortMap.put("C", 70);

        System.out.println("Before sorting......");
        printMap(unsortMap);

        System.out.println("After sorting ascending order......");
        Map<String, Integer> sortedMapAsc = sortByComparator(unsortMap, ASC);
        printMap(sortedMapAsc);


        System.out.println("After sorting descindeng order......");
        Map<String, Integer> sortedMapDesc = sortByComparator(unsortMap, DESC);
        printMap(sortedMapDesc);

    }

    private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap, final boolean order)
    {

        List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(unsortMap.entrySet());

        // Sorting the list based on values
        Collections.sort(list, new Comparator<Entry<String, Integer>>()
        {
            public int compare(Entry<String, Integer> o1,
                    Entry<String, Integer> o2)
            {
                if (order)
                {
                    return o1.getValue().compareTo(o2.getValue());
                }
                else
                {
                    return o2.getValue().compareTo(o1.getValue());

                }
            }
        });

        // Maintaining insertion order with the help of LinkedList
        Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
        for (Entry<String, Integer> entry : list)
        {
            sortedMap.put(entry.getKey(), entry.getValue());
        }

        return sortedMap;
    }

    public static void printMap(Map<String, Integer> map)
    {
        for (Entry<String, Integer> entry : map.entrySet())
        {
            System.out.println("Key : " + entry.getKey() + " Value : "+ entry.getValue());
        }
    }
}
Evildoer answered 17/12, 2012 at 11:31 Comment(0)
H
2

You could try giving a Comparator that compare values instead of keys when you create the TreeMap.

    final TreeMap<Integer,String> tree = new TreeMap<Integer,String>();
    tree.put(1, "1");
    tree.put(2, "2");
    tree.put(3, "3");
    tree.put(4, "4");

    final TreeMap<Integer,String> treeSortedByValues = new TreeMap<Integer,String>(new Comparator<Integer>()
    {
        public int compare(Integer o1, Integer o2)
        {
            return tree.get(o1).compareTo(tree.get(o2));
        }
    });
    treeSortedByValues.putAll(tree);

    for ( Entry<Integer, String> e : treeSortedByValues.entrySet() )
    {
        System.out.println(e.getKey() + ": " + e.getValue());
    }
Henning answered 19/9, 2009 at 11:28 Comment(3)
How will the comparator get access to the values ?Vorlage
It won't. This isn't possible with the TreeMap.Anthropologist
True, you cannot access the treemap values in the comparator since the treemap is not created yet. But you can use a temporary treemap for that...Henning
V
0

Swap values and keys.

More seriously, please provide some context what you want to achieve. Maybe it is enough to sort after other processing is finished.

Vlaminck answered 19/9, 2009 at 11:28 Comment(2)
He means you should use whatever you're using as key now as the value, and vice versa. That way you can sort on your value, which is now the key.Anthropologist
This is generally a poor approach since the map has unique keys (with respect to compareTo) but not necessarily unique values. Create a new map with keys swapped with values might give you a different data set.Velarium
M
0

Try this. This sorts TreeMap values in ascending order, assuming that is how you want the values to be sorted.

static <K, V> Map<K, V> sortByValues(Map<K, V> map) {
        List<?> list = new ArrayList(map.entrySet());

        // copy Map to List to use Comparator
        Collections.sort(list, new Comparator() {
            public int compare(Object o1, Object o2) {
                return ((Comparable) ((Map.Entry) o1).getValue()).compareTo(((Map.Entry) o2).getValue());
            }
        });

        // then copy List to LinkedHashMap as it preserves insertion order
        Map<K, V> result = new LinkedHashMap<K, V>();
        Iterator itr = list.iterator();
        while (itr.hasNext()) {
            Map.Entry<K, V> m = (Map.Entry<K, V>) itr.next();
            result.put(m.getKey(), m.getValue());
        }

        return result;
    }
Milan answered 27/5, 2020 at 12:21 Comment(0)
E
-1

That's I have done this..

package Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

class MyComparator implements Comparator<Object> {

    public int compare(Object o1, Object o2) {
        return (((Integer) o2).compareTo((Integer) o1));
    }
}

class MyComparator1 implements Comparator<Object> {
    Map<Integer, String> map;

    public MyComparator1(Map<Integer, String> m) {
        this.map = m;
    }

    public int compare(Object o1, Object o2) {
        return (((String) map.get(o1)).compareTo((String) map.get(o2)));
    }
}

public class Map1 {
    public static void main(String[] args) {
        Map<Integer, String> hmap = new HashMap<Integer, String>();
        hmap.put(5, "Ashok");
        hmap.put(21, "Bhanu");
        hmap.put(7, "chaman");
        hmap.put(28, "dheeraj");
        hmap.put(761, "edison");
        hmap.put(1, "frank");
        hmap.put(-6, "gopal");
        hmap.put(78, "hari");
        System.out.println("Hash Map:" + hmap);
        Map<Integer, String> tmap = new TreeMap<>(hmap);
        System.out.println("Tree Map:" + tmap);
        MyComparator comp = new MyComparator();
        Map<Integer, String> itmap = new TreeMap<>(comp);
        itmap.putAll(hmap);
        System.out.println("Tree Map Inreverse order:" + itmap);
        Map<Integer, String> orderValuemap = new TreeMap<Integer, String>(new 
            MyComparator1(hmap));
            orderValuemap.putAll(hmap);
            orderValuemap.put(22,"hello");
        for(Entry<Integer, String> mp:orderValuemap.entrySet())
            System.out.println("Value : "+mp.getValue());
    }
}
Eventuate answered 28/11, 2017 at 10:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.