如何使用值对 LinkedHashMap 进行排序?
有没有办法将条目插入到 LinkedHashMap 中,以便它们根据其值按顺序插入?
如何使用值对 LinkedHashMap 进行排序?
LinkedHashMap
不是 已排序,而是按插入顺序 有序。
如果您的目标是重新排序地图,您可能会这样做
static <K, V> void orderByValue(
LinkedHashMap<K, V> m, final Comparator<? super V> c) {
List<Map.Entry<K, V>> entries = new ArrayList<>(m.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> lhs, Map.Entry<K, V> rhs) {
return c.compare(lhs.getValue(), rhs.getValue());
}
});
m.clear();
for(Map.Entry<K, V> e : entries) {
m.put(e.getKey(), e.getValue());
}
}
我们将所有条目放入列表中,对列表进行排序,然后将条目按新顺序放回到映射中。
这里有一个 Java 8 翻译,供有兴趣的人参考:
static <K, V> void orderByValue(
LinkedHashMap<K, V> m, Comparator<? super V> c) {
List<Map.Entry<K, V>> entries = new ArrayList<>(m.entrySet());
m.clear();
entries.stream()
.sorted(Comparator.comparing(Map.Entry::getValue, c))
.forEachOrdered(e -> m.put(e.getKey(), e.getValue()));
}
(出于好奇,可以将其压缩为,尽管效率较低):
static <K, V> void orderByValue(
LinkedHashMap<K, V> m, Comparator<? super V> c) {
new ArrayList<>(m.keySet()).stream()
.sorted(Comparator.comparing(m::get, c))
.forEachOrdered(k -> m.put(k, m.remove(k)));
}
有没有办法将条目插入到 LinkedHashMap 中,以便它们根据其值按顺序插入?
不。往上看。
LinkedHashMap
未排序。
如果您的目标是保持地图排序,则需要使用
TreeMap
;然而这样做存在一些问题。地图中的条目需要具有唯一的值。请参阅此处和此处。
我认为按值对
LinkedHashMap
进行排序的最佳方法是编写一个比较器,按值比较两个 Map.Entry<K,V>
对象,然后
Map.Entry<K,V>[] entries = (Map.Entry<K,V>[])map.entrySet().toArray();
Arrays.sort(entries, comparator);
比较器看起来像这样
Comparator<Map.Entry<K,V>> comparator = new Comparator<Map.Entry<K,V>>() {
@Override
public int compare(Map.Entry<K,V> o1, Map.Entry<K,V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
};
基本上,这是显而易见的事情:创建映射中所有键/值对的数组,然后对其进行排序。 注意:我还没有测试过这个。
对于第二个问题:这需要一个特殊的数据结构来按顺序维护值。当你插入一个元素时,它会建立哈希表并且按照插入顺序维护元素的双向链表并且建立某种AVL树来保持值的顺序,就像
TreeSet
一样。我不认为Java定义了这样的类,但也许第三方库中有一个。维护两个独立的结构可能是最简单的,一个 LinkedHashMap<K,V>
和一个 TreeSet<Map.Entry<K,V>>
。
就像我之前的答案一样,LinkedHashMap 没有排序,它只保存插入顺序。您必须手动创建比较器。
现在的问题是你要根据什么对地图进行排序?通过整数键...
这是一个例子:(树状图)
// Create a hash map
TreeMap tm = new TreeMap();
// Put elements to the map
tm.put("person1", new Double(1));
tm.put("person2", new Double(2));
tm.put("person3", new Double(3));
tm.put("person4", new Double(4));
tm.put("person5", new Double(5));
// Get a set of the entries
Set set = tm.entrySet();
// Get an iterator
Iterator i = set.iterator();
// Display elements
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
// Deposit 1000 into person5's account
double balance = ((Double)tm.get("person5")).doubleValue();
tm.put("person5", new Double(balance + 1000));
System.out.println("person5's new balance: " +
tm.get("person5"));
这棵树将按键的自然顺序排序。即 person1 扔了 person5
person1: 1.00
person2: 2.00
person3: 3.00
person4: 4.00
person5: 5.00
person5's new balance: 1005.00
public class MyTMCompUserDefine {
public static void main(String a[]){
//By using name comparator (String comparison)
TreeMap<Empl,String> tm = new TreeMap<Empl, String>(new MyNameComp());
tm.put(new Empl("Ram",3000), "RAM");
tm.put(new Empl("John",6000), "JOHN");
tm.put(new Empl("Crish",2000), "CRISH");
tm.put(new Empl("Tom",2400), "TOM");
Set<Empl> keys = tm.keySet();
for(Empl key:keys){
System.out.println(key+" ==> "+tm.get(key));
}
System.out.println("===================================");
//By using salary comparator (int comparison)
TreeMap<Empl,String> trmap = new TreeMap<Empl, String>(new MySalaryComp());
trmap.put(new Empl("Ram",3000), "RAM");
trmap.put(new Empl("John",6000), "JOHN");
trmap.put(new Empl("Crish",2000), "CRISH");
trmap.put(new Empl("Tom",2400), "TOM");
Set<Empl> ks = trmap.keySet();
for(Empl key:ks){
System.out.println(key+" ==> "+trmap.get(key));
}
}
}
class MyNameComp implements Comparator<Empl>{
@Override
public int compare(Empl e1, Empl e2) {
return e1.getName().compareTo(e2.getName());
}
}
class MySalaryComp implements Comparator<Empl>{
@Override
public int compare(Empl e1, Empl e2) {
if(e1.getSalary() > e2.getSalary()){
return 1;
} else {
return -1;
}
}
}
class Empl{
private String name;
private int salary;
public Empl(String n, int s){
this.name = n;
this.salary = s;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString(){
return "Name: "+this.name+"-- Salary: "+this.salary;
}
}
Output:
Name: Crish-- Salary: 2000 ==> CRISH
Name: John-- Salary: 6000 ==> JOHN
Name: Ram-- Salary: 3000 ==> RAM
Name: Tom-- Salary: 2400 ==> TOM
===================================
Name: Crish-- Salary: 2000 ==> CRISH
Name: Tom-- Salary: 2400 ==> TOM
Name: Ram-- Salary: 3000 ==> RAM
Name: John-- Salary: 6000 ==> JOHN
将 LinkedHashMap 转换为排序列表,然后执行您想要的操作:
LinkedHashMap<String, BigDecimal> topCosts = data.getTopCosts();
List<Map.Entry<String, BigDecimal>> entries = topCosts.entrySet()
.stream()
.sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) // desc
.collect(Collectors.toList());
for (Map.Entry<String, BigDecimal> entry : entries) {
// do somting..
}