根据大小对地图进行排序

时间:2014-09-03 07:40:31

标签: java

我有这样的地图:

Map<List<Item>, Double> items = new HashMap<List<Item>, Double>();

我想根据最大尺寸的List<Item>的大小对此hashmap进行排序。我不关心相同大小的对象中的排序。

到目前为止,我尝试使用TreeSet,如此:

SortedSet<Map.Entry<List<Item>, Double>> sortedItems = new TreeSet<Map.Entry<List<Item>, Double>>(
     new Comparator<Map.Entry<List<Item>, Double>>() {

        @Override
        public int compare(
            Entry<List<Item>, Double> o1,
            Entry<List<Item>, Double> o2) {
               return o2.getKey().size() - o1.getKey().size();
        }
    });
sortedItems.addAll(items.entrySet());

但是,sortedItems对象只占用每个大小的列表中的一个。它将同等大小的列表视为重复列表并忽略它们。我该如何解决这个问题。

编辑:从我所知,当比较2个相同大小的列表时,我的compare方法正在返回0。这告诉集合条目是相等的,它们被视为重复。所以我想解决这个问题的唯一方法是确保compare方法永远不会返回0。所以我写了这段代码:

@Override
public int compare(
    Entry<List<AuctionItem>, Double> o1,
    Entry<List<AuctionItem>, Double> o2) {
        if (o1.getKey().size() <= o2.getKey().size()) {
            return -1;
        } else {
            return 1;
        }
}

4 个答案:

答案 0 :(得分:3)

您正在使用TreeSet Comparator,根据compare()的实现,如果列表大小相同,则返回0。由于TreeSet不能包含重复项,因此它只添加其中一个大小相等的列表。您无需创建TreeSet即可对Map进行排序,因为当元素类似于数学集(无重复元素)时,应使用 SETS 。你可能会这样做:

List<Map.Entry<List<Item>, Double>> list =
        new LinkedList<Map.Entry<List<Item>, Double>>( map.entrySet() );

Collections.sort( list, new Comparator<Map.Entry<List<Item>, Double>>()
        {
            public int compare( Map.Entry<List<Item>, Double> o1, Map.Entry<List<Item>, Double> o2 )
            {
                return (o1.getKey().size().compareTo( o2.getKey.size() );
            }
        } );

也就是说,将map的条目放在List中,然后对列表进行排序。

答案 1 :(得分:1)

您使用值列表(项)作为哈希映射的关键字似乎很奇怪;但是,我会试一试。

核心任何地图都不是有序集合。简而言之,如果&#34; Pete&#34;高度为67英寸,&#34; Bob&#34;高度为72英寸,然后没有一些额外的信息,无法确定Bob是应该在Pete之前还是之后来。

按键&#34;键&#34;或者在这种情况下,&#34; name&#34;一个人可能会强制使用字母排序,在这种情况下,&#34; Bob&#34;来自&#34; Pete&#34;。

由&#34;值&#34;订购或者在这种情况下,&#34;身高&#34;一个人可能会施加最小到最大的排序,在这种情况下&#34; Pete&#34;来自&#34; Bob&#34;。

我确定你知道你想要订购什么(列表的大小),但是这个例子意味着说明单独的Map是一个糟糕的数据结构用于排序。甚至Java中的有序映射也只按插入顺序排序。

我的建议是将两个集合保存在同一个包装类中。一个包含键的有序列表,另一个包含Map。如果您希望按照其关键特征获得有序的值集,请按顺序列出有序键并按顺序返回映射值。它更容易理解,更易读。

同时也意识到Map没有监听键值,因此,如果某个拥有键的人决定将该条目添加到该键所维护的List中,则Map将不知道该更改并且不会重新计算密钥的前值。因此,要正确使用Map,您需要以两种方式之一来处理它。

  1. 使映射键不可变,在输入时复制值并在输出上返回Collections.unmodifiableList(...)包装。
  2. 接受可以收听的地图密钥,并使地图成为可能发生的密钥更新的订阅者。当地图检测到密钥更改时,将从旧密钥位置删除这些值,并使用新密钥重新添加回地图。

答案 2 :(得分:1)

如果您尝试将某个项目放入自定义TreeSet返回Comparator的{​​{1}},则 项将不会放入{{ 1}}。

您必须使用不返回0的{​​{1}}。对于大小相等的Set,您必须定义一致任意顺序。

这是一种简单易行的方法:

Comparator

基本上我做的是:如果2个列表的大小不同,0就可以了。如果它们具有相同的大小,我将返回其标识哈希码的差异,它总是与List不同,因为标识哈希码是不同的内存地址对于不同的对象。并且它对于一个对象总是相同的,因此比较器将始终为具有相同大小的两个列表返回相同的顺序。

使用此比较器,您将获得一个排序集,允许列表具有相同的大小,并按列表大小排序。

答案 3 :(得分:0)

如果您不需要随着时间的推移不断进行排序,您可以这样做:

Map<List<Item>, Double> items = new HashMap<>();

List<Map.Entry<List<Item>, Double>> list = new ArrayList<>(items.entrySet());
Collections.sort(list, new Comparator<Map.Entry<List<Item>, Double>>() {
        @Override
        public int compare(
          Map.Entry<List<Item>, Double> o1,
          Map.Entry<List<Item>, Double> o2) {
          return Integer.compare(o2.getKey().size(), o1.getKey().size());
        }
    }

});

如果您需要TreeSetTreeMap,那么使用Comparator就可以了,但您需要定义当列表大小等于时会发生什么:您需要使用其他条件来确定排序(例如比较两个列表中的每个项目a,b,直到a.compareTo(b) != 0)。