反向哈希图

Reverse HashMap

我有一个 HashMap 看起来像 :

HashMap<Player, Integer> playerHashMap = new HashMap<>();

Player 是包含姓名、号码、年龄等的对象

现在我已经对它进行了排序,它看起来像这样:

key    , value
-----------------
Player1, 1
Player2, 2
Player3, 4
Player4, 6

但是我想实现按值反转这张图,像这样:

key    , value
-----------------
Player4, 6
Player3, 4
Player2, 2
Player1, 1

有什么想法吗?

排序方法(按值排序)如下所示:

private static HashMap<Player, Integer> sortByValues(HashMap<Player, Integer> map) { 
           List list = new LinkedList(map.entrySet());

           Collections.sort(list, new Comparator<Object>() {
                public int compare(Object o1, Object o2) {
                   return ((Comparable) ((Map.Entry) (o1)).getValue())
                      .compareTo(((Map.Entry) (o2)).getValue());
                }
           });

           HashMap<Player, Integer> sortedHashMap = new LinkedHashMap<Player, Integer>();
           for (Iterator<?> it = list.iterator(); it.hasNext();) {
                Map.Entry<Player, Integer> entry = (Map.Entry<Player, Integer>) it.next();
                  sortedHashMap.put(entry.getKey(), entry.getValue());
           } 
           return sortedHashMap;
      }

事实是 HashMap 不保证任何特定的迭代顺序。所以你只是 'got lucky' 你的列表以任何方式排序。要解决您的问题,您必须将 table 行作为一个实体进行排序,以便 value 链接到相应的 player。为此,您实际上可以直接使用 Map.Entry,并将它们放入集合中,但您需要一个自定义比较器。在您的示例中,最好使用通常的 ArrayList 来完成任务,并使用 Collections.sort() 对其进行排序。要颠倒顺序,请从比较器中否定您 return 的结果:

class Player {}

public static void main(String[] args) {
    HashMap<Player, Integer> all = new HashMap<>();
    List<Map.Entry<Player, Integer>> sorted = sortByValues(all);
    for (Map.Entry<Player, Integer> e : sorted) {
        System.out.println("Player: " + e.getKey());
        System.out.println("Value: " + e.getValue());
    }
}

private static List<Map.Entry<Player, Integer>> sortByValues(HashMap<Player, Integer> map) {
    List<Map.Entry<Player, Integer>> list = new ArrayList<>(map.entrySet());

    Collections.sort(list, new Comparator<Map.Entry<Player, Integer>>() {
        public int compare(Map.Entry<Player, Integer> e1, Map.Entry<Player, Integer> e2) {
            //use minus to reverse the order
            return -e1.getValue().compareTo(e2.getValue());
        }
    });

    return list;
}

你是怎么排序的? (基本)HashMap 不定义元素之间的顺序。 我用这个:

    public static <K extends Comparable<K>,V> List<Entry<K,V>> sortByKeys(Map<K,V> map, final Comparator<K> cmp)
{
    List<Entry<K, V>> ret = new ArrayList<>();
    for(Entry<K,V> kv : map.entrySet())
        ret.add(kv);


    Collections.sort(ret,((Comparator) new Comparator<Entry<K,?>>()
    {
        @Override
        public int compare(Entry<K, ?> o1, Entry<K, ?> o2)
        {
            return cmp.compare(o1.getKey(), o2.getKey());
        }
    }));

    return ret;
}

您可以指定您的比较器来对返回的挂单列表进行排序。

=====

编辑: 使用关心顺序的 Map 实现是个好主意。 您可以简单地修改您的代码以指定排序,只需修改 header 和这一行:

-private static HashMap<Player, Integer> sortByValues(HashMap<Player, Integer> map) {
+private static HashMap<Player, Integer> sortByValues(HashMap<Player, Integer> map, final boolean reverse) {

并在块中:

-return ((Comparable) ((Map.Entry) (o1)).getValue())
+return (reverse?-1:1)*((Comparable) ((Map.Entry) (o1)).getValue())

您可以使用 java.util.TreeMap 并传递比较器以按照您想要的方式对它们进行排序。

但是我仍然想知道为什么您将 Player 作为 Key 而将 Integer 作为 Value ? 如果您仅使用 Integer 进行排序,那么您可能希望交换 Key 和 value 以更好地使用 Maps 的标准方式。 此外,如果您不需要使用哈希技术访问对象(也就是说,如果您的集合不会很大,哈希会提高性能)考虑一个简单的列表。

我不确定您为什么要 return 单独映射。您已经有了 List,您可以简单地按存储条目的值进行排序。
也不要限制自己使用特定类型的映射,例如 HashMap。您可能一无所获,但很难将您的实现更改为其他类型的 Map。

因此您的代码可能如下所示:

private static List<Map.Entry<Player, Integer>> entriesSoltedByValue(
        Map<Player, Integer> map) {
    List<Map.Entry<Player, Integer>> list = new ArrayList<>(map.entrySet());

    list.sort(Comparator.comparing(Map.Entry<Player, Integer>::getValue).reversed());

    return list;
}

或使用流:

private static List<Map.Entry<Player, Integer>> entriesSoltedByValue(
        Map<Player, Integer> map) {
    return map.entrySet()
            .stream()
            .sorted(Comparator
                    .comparing(Map.Entry<Player, Integer>::getValue)
                    .reversed())
            .collect(Collectors.toList());
}

简而言之,您不能将订单设置为 HashMap。如果您想要与 HashMap 相同的功能但有顺序,您应该使用 TreeMap.

Map<String, Integer> orderedMap = new TreeMap(Collections.reverseOrder());
orderedMap.putAll(playerHashMap);

HashMap 给你 O(1) 插入和搜索,而它们在 TreeMap 中是 O(log(n)) 因为它是在内部用红黑树实现的。