我有这样的地图:
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;
}
}
答案 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,您需要以两种方式之一来处理它。
Collections.unmodifiableList(...)
包装。答案 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());
}
}
});
如果您需要TreeSet
或TreeMap
,那么使用Comparator
就可以了,但您需要定义当列表大小等于时会发生什么:您需要使用其他条件来确定排序(例如比较两个列表中的每个项目a,b,直到a.compareTo(b) != 0
)。