如何使用值对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());
}
}
我们将所有条目放入List中,对List进行排序,然后按照新顺序将条目放回Map中。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()));
}
< p >(出于好奇,可以概括为,尽管效率较低):< /p >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
没有排序功能。
如果您的目标是保持Map的排序,则需要使用TreeMap
;但是这样做会存在问题。地图中的条目需要具有唯一值。请参见此处和此处。
TreeMap
来对LinkedHashMap
进行排序(例如TreeMap<...> tm = new TreeMap<>(lhm, valueComparator); lhm.clear(); lhm.putAll(tm);
),我不认为这是一个好主意。要么值必须是唯一的,要么你需要一个hack比较器。 - RadiodefMap
,但它不会有任何效果。我想如果Java有一个像OrderedMap<K, V>
这样的接口,即使只是一个标记,LinkedHashMap
也可以实现,那就太好了。 - Radiodefstatic <K, V> void orderByValue
?我就是不明白...这种语法通常不是用于参数化类型吗?据我所知,这块似乎没有任何需要参数化的东西...有人能解释一下吗? - SebasSBMComparator<? super V>
基本上就是一个Comparator<V>
,但它对于您可以传递到方法中的内容有一些更宽松的限制。) 您可以通过使用原始类型编写等效的方法,但强烈不建议使用原始类型。 - Radiodef我认为对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并没有排序功能,它只保存插入顺序。您需要手动创建比较器。
现在的问题是希望按什么方式对Map进行排序?按整数键排序...
这里有一个例子:(Tree Map)
// 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<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..
}
LinkedHashMap
进行排序的目的是什么?也许可以使用TreeMap
,并提供自己的Comparator
来对值进行排序,而不是对键进行排序。 - Tom