Как отсортировать карту дерева на основе ее значений?

Как я могу отсортировать карту дерева, используя ее значения, а не ключ?


person Ali    schedule 19.09.2009    source источник
comment
Первое решение по этой ссылке — лучшее, что у вас может быть. stackoverflow.com/questions/2864840/treemap-sort-by-value   -  person shikher.mishra    schedule 09.03.2016


Ответы (9)


Вы не можете, поскольку компаратор TreeMap работает только с ключами, например. см. этот конструктор.

В любом случае, вы можете использовать несколько коллекций, использовать TreeMap (или, скорее, HashMap) для поиска элементов по ключам и иметь SortedSet для итерации значений.

person Zed    schedule 19.09.2009

Вот решение:

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

Обратите внимание, что карта отсортирована от наибольшего значения к наименьшему.

person Anthony    schedule 21.01.2010
comment
Я получаю исключение stackoverflow с помощью этого метода - person superrache; 30.11.2015
comment
это на самом деле не работает! если только все данные не находятся в исходном Map<K,V> map и вам никогда не нужно вводить новые значения - person Leonmax; 07.10.2016


Коллекция Apache Commons имеет TreeBidiMap:

Этот класс гарантирует, что карта будет находиться как в порядке возрастания ключа, так и в порядке возрастания значения, отсортированного в соответствии с естественным порядком для классов ключа и значения.

Его порт для Java5-дженериков здесь.

person skaffman    schedule 19.09.2009

Попробуйте код ниже, он отлично работает для меня. Вы можете выбрать как восходящий, так и нисходящий порядок сортировки.

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());
        }
    }
}
person Rais Alam    schedule 17.12.2012

Вы можете попробовать дать Comparator, который сравнивает значения вместо ключей при создании 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());
    }
person Vincent Robert    schedule 19.09.2009
comment
Как компаратор получит доступ к значениям? - person Zed; 19.09.2009
comment
Это не будет. Это невозможно с TreeMap. - person Jorn; 19.09.2009
comment
Правда, вы не можете получить доступ к значениям карты дерева в компараторе, так как карта дерева еще не создана. Но вы можете использовать для этого временную древовидную карту... - person Vincent Robert; 19.09.2009

Поменять местами значения и ключи.

А если серьезно, предоставьте некоторый контекст, чего вы хотите достичь. Может быть, достаточно отсортировать после завершения другой обработки.

person starblue    schedule 19.09.2009
comment
Он имеет в виду, что вы должны использовать то, что сейчас используете в качестве ключа, в качестве значения, и наоборот. Таким образом, вы можете сортировать по своему значению, которое теперь является ключом. - person Jorn; 19.09.2009
comment
Как правило, это плохой подход, поскольку карта имеет уникальные ключи (относительно compareTo), но не обязательно уникальные значения. Создание новой карты с заменой ключей значениями может дать вам другой набор данных. - person Buhb; 19.09.2009

Это я сделал это..

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());
    }
}
person Ritwik Jain    schedule 28.11.2017

Попробуй это. Это сортирует значения TreeMap в порядке возрастания, предполагая, что именно так вы хотите отсортировать значения.

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;
    }
person Iy 716    schedule 27.05.2020