【问题标题】:Reverse HashMap反向哈希映射
【发布时间】:2016-01-31 20:32:36
【问题描述】:

我有一个HashMap,看起来像:

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

玩家是包含姓名、号码、年龄等的对象。

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

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 不保证任何顺序。如果您的意思是您能够按照描述的顺序打印它们而不是阻止您以不同的顺序打印它们?
  • 你是如何“排序”你的 HashMap 的?代码在哪里?
  • 我编辑了我的帖子并添加了外观方法来排序 HashMap。
  • 嗯,很难想象有更低效的方式来实现这种排序......
  • 我猜你真正想做的是将HashMap&lt;Player, Integer&gt; 转换为HashMap&lt;Integer, Player&gt;。您无需进行任何排序即可实现这一目标。

标签: java hashmap reverse sorted


【解决方案1】:

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

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

【讨论】:

  • Key 是 Player,因为我需要访问他的所有信息,Value 是 Integer,因为它代表我之前计算和增加的进球数。
  • 如果排序是您唯一需要完成的事情,您可以通过反转 compareTo 方法中的项目来做到这一点,(交换 o1 和 o2)或在返回之前添加 - 到表达式 - ((Comparable) ((Map.Entry) (o1)).getValue()) .compareTo(((Map.Entry) (o2)).getValue());无论哪种方式,我仍然会重新考虑设计,要么将 no.of 目标作为键,要么作为 Player 对象中的属性。但是我会把这个决定留给你,因为你更了解这个应用程序。尝试上述调整以对它们进行反向排序。
【解决方案2】:

你是怎么排序的? (基本)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 实现是个好主意。 您可以简单地修改您的代码以指定排序,只需修改标题和这一行:

-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 元素中通过比较器的返回值(正、负或零)应用比较。在后台 java 调用比较器,需要比较两个元素,并通过返回值排序算法决定要做什么。值的大小并不关心它是负数、零或空值。因此,如果您不更改比较器返回值的符号,则会得到升序映射,如果这样做(乘以 -1),则会得到相反的顺序。
【解决方案3】:

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

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

【讨论】:

  • 它看起来也不错 ;)
【解决方案4】:

我不确定您为什么要返回单独的地图。您已经拥有 List ,您可以简单地按存储条目的值进行排序。
也不要限制自己使用特定类型的 Map,如 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());
}

【讨论】:

    【解决方案5】:

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

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

    HashMapTreeMap 中为您提供 O(1) 插入和搜索,而它们是 O(log(n)),因为它在内部使用红黑树实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-29
      • 1970-01-01
      • 1970-01-01
      • 2018-10-13
      • 2016-04-23
      • 1970-01-01
      相关资源
      最近更新 更多