这基本上不是基于键对HashMap
进行排序的方法。为此我可以直接使用TreeMap
而不用眨眼:)
目前我所拥有的是
Map<String, Object> favoritesMap = new HashMap<String, Object>();
and its contents can be
["Wednesdays" : "abcd"]
["Mondays" : "1234"]
["Not Categorized" : "pqrs"]
["Tuesdays" : "5678"]
我想基于键对HashMap进行排序,除此之外,我需要“未分类”作为最后一个检索。
在迭代keySet时所期望的是
["Mondays", "Tuesdays", "Wednesdays", "Not Categorized"] i.e. sorted on keys and "Not Categorized" is the last one
考虑在创建时选择HashMap
,最后添加["Not Categorized" : "pqrs"]
,但HashMap
不保证订单:)
解决方案的其他任何指针?
答案 0 :(得分:5)
出于某些外部原因,您是否明确排除了TreeMap
?如果不是,您显然可以将TreeMap
与特制的Comparator
一起使用。
您是否考虑了其他任何SortedMap
?
如果TreeMap
肯定是出局的话,我会延长HashMap
并使它看起来总是有一个条目,但这肯定不是一件微不足道的工作。在走这条路之前,你应该有充分的理由不使用SortedMap
。
<强>加强>
以下是一个示例,说明如何使用TreeMap
使特定条目始终排在最后:
// This key should always appear at the end of the list.
public static final String AtEnd = "Always at the end";
// A sample map.
SortedMap<String, String> myMap =
new TreeMap<>(
new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.equals(AtEnd) ? 1 : o2.equals(AtEnd) ? -1 : o1.compareTo(o2);
}
});
private void test() {
myMap.put("Monday", "abc");
myMap.put("Tuesday", "def");
myMap.put("Wednesday", "ghi");
myMap.put(AtEnd, "XYZ");
System.out.println("myMap: "+myMap);
// {Monday=abc, Tuesday=def, Wednesday=ghi, Always at the end=XYZ}
}
我想知道你是否正在寻找一些变体?
答案 1 :(得分:3)
您可以使用LinkedHashMap
来实现此目的,因为它可以保证按插入顺序返回结果。
另请查看以下帖子,了解地图类型之间的区别。
或者只是创建一个包含与值不同的键的自定义类。根据该类的键进行排序。对于您的情况,使密钥与日期相同,对于“未分类”的情况,确保其密钥的启动时间晚于任何其他密钥,例如将其设置为“Z_Not Categorized”。
public ComplexKey
{
String key;
String value;
}
ComplexKey monday = new ComplexKey("monday", "monday");
ComplexKey notCategorized = new ComplexKey("Z_Not Categorized", "Not Categorized");
然后你可以编写一个自定义比较器,根据complexKey
类的键对值进行排序。
答案 2 :(得分:1)
在你的情况下,我会使用TreeMap:
Map<DayOfWeek, Object> favoritesMap = new TreeMap<>();
其中DayOfWeek
是您声明的类:
class DayOfWeek implements Comparable<DayOfWeek> {
因为把日子作为字符串排序是不方便的。
答案 3 :(得分:1)
实际上,键总是排序的。如果您多次输出地图,您会发现结果保持不变。
原因是哈希。每个对象都有hashCode()
方法。哈希空间就像一个大型数组,它包含所有可能的哈希值作为索引。将新元素插入HashSet
或将新对放入HashMap
时,根据其哈希码将其放置在哈希空间中。如果两个元素具有相同的哈希码,则将它们与equals()
方法进行比较,如果不相等,则将新元素放在其旁边。
import java.util.*;
class MyString {
private String str;
public MyString (String str) {
this.str = str;
}
public String toString () {
return str;
}
public boolean equals (Object obj) {
if (obj.getClass().equals(MyString.class)) {
return obj.toString().equals(str);
}
return false;
}
public int hashCode () {
if (str.equalsIgnoreCase("Not Categorized")) {
return Integer.MAX_VALUE;
} else if (str.hashCode() == Integer.MAX_VALUE) {
return 0;
}
return str.hashCode();
}
}
public class Test {
public static void main (String args[]) {
Map<MyString, String> m = new HashMap<MyString, String>();
m.put(new MyString("a"), "a");
m.put(new MyString("c"), "c");
m.put(new MyString("Not Categorized"), "NC");
m.put(new MyString("b"), "b");
Set<MyString> keys = m.keySet();
for (MyString k : keys) {
System.out.println(m.get(k));
}
}
}
结果是“未分类”总是最后出现。原因很简单:它的哈希值始终是整数的最大值。
我创建String包装类的原因是String类是final,它不能被扩展。因此,通过这种方式,您的班级结构会有一点变化,但不会太多。
public static void main (String args[]) {
Map<String, String> m = new TreeMap<String, String>(new Comparator<String>() {
public int compare (String s1, String s2) {
if (s1.equals(s2)) {
return 0;
}
if (s1.equalsIgnoreCase("Not Categorized")) {
return 1;
}
if (s2.equalsIgnoreCase("Not Categorized")) {
return -1;
}
if (s1.hashCode() > s2.hashCode()) {
return 1;
} else if (s1.hashCode() < s2.hashCode()) {
return -1
} else {
return 0;
}
}
public boolean equals (Object obj) {
return false;
}
});
m.put("a", "a");
m.put("c", "c");
m.put("Not Categorized", "NC");
m.put("b", "b");
Set<String> keys = m.keySet();
for (String k : keys) {
System.out.println(m.get(k));
}
}