我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
当前回答
我合并了user157196和Carter Page的解决方案:
class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue( Map<K, V> map ){
ValueComparator<K,V> bvc = new ValueComparator<K,V>(map);
TreeMap<K,V> sorted_map = new TreeMap<K,V>(bvc);
sorted_map.putAll(map);
return sorted_map;
}
}
class ValueComparator<K, V extends Comparable<? super V>> implements Comparator<K> {
Map<K, V> base;
public ValueComparator(Map<K, V> base) {
this.base = base;
}
public int compare(K a, K b) {
int result = (base.get(a).compareTo(base.get(b)));
if (result == 0) result=1;
// returning 0 would merge keys
return result;
}
}
其他回答
public class Test {
public static void main(String[] args) {
TreeMap<Integer, String> hm=new TreeMap();
hm.put(3, "arun singh");
hm.put(5, "vinay singh");
hm.put(1, "bandagi singh");
hm.put(6, "vikram singh");
hm.put(2, "panipat singh");
hm.put(28, "jakarta singh");
ArrayList<String> al=new ArrayList(hm.values());
Collections.sort(al, new myComparator());
System.out.println("//sort by values \n");
for(String obj: al){
for(Map.Entry<Integer, String> map2:hm.entrySet()){
if(map2.getValue().equals(obj)){
System.out.println(map2.getKey()+" "+map2.getValue());
}
}
}
}
}
class myComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
String o3=(String) o1;
String o4 =(String) o2;
return o3.compareTo(o4);
}
}
输出,输出=
//sort by values
3 arun singh
1 bandagi singh
28 jakarta singh
2 panipat singh
6 vikram singh
5 vinay singh
在TreeMap中,键按自然顺序排序。例如,如果您对数字进行排序,(注意4的排序)
{0=0, 10=10, 20=20, 30=30, 4=4, 50=50, 60=60, 70=70}
要解决这个问题,在Java8中,首先检查字符串长度,然后进行比较。
Map<String, String> sortedMap = new TreeMap<>Comparator.comparingInt(String::length)
.thenComparing(Function.identity()));
{0=0, 4=4, 10=10, 20=20, 30=30, 50=50, 60=60, 70=70}
要使用Java 8中的新功能实现这一点,请执行以下操作:
import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;
<K, V> List<Entry<K, V>> sort(Map<K, V> map, Comparator<? super V> comparator) {
return map.entrySet().stream().sorted(comparingByValue(comparator)).collect(toList());
}
条目使用给定的比较器按其值排序。或者,如果您的值可以相互比较,则不需要显式比较器:
<K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
return map.entrySet().stream().sorted(comparingByValue()).collect(toList());
}
返回的列表是调用此方法时给定映射的快照,因此两者都不会反映对另一个的后续更改。对于地图的实时可迭代视图:
<K, V extends Comparable<? super V>> Iterable<Entry<K, V>> sort(Map<K, V> map) {
return () -> map.entrySet().stream().sorted(comparingByValue()).iterator();
}
返回的可迭代对象在每次迭代时都会创建给定映射的新快照,因此除非并发修改,否则它将始终反映映射的当前状态。
这是Anthony答案的变体,如果存在重复值,则该答案无效:
public static <K, V extends Comparable<V>> Map<K, V> sortMapByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
final V v1 = map.get(k1);
final V v2 = map.get(k2);
/* Not sure how to handle nulls ... */
if (v1 == null) {
return (v2 == null) ? 0 : 1;
}
int compare = v2.compareTo(v1);
if (compare != 0)
{
return compare;
}
else
{
Integer h1 = k1.hashCode();
Integer h2 = k2.hashCode();
return h2.compareTo(h1);
}
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
注意,如何处理空值还很难说。
这种方法的一个重要优点是它实际上返回了一个Map,这与这里提供的其他解决方案不同。
用Java中最简单的方式对任何Hashmap进行排序。我们不需要将其存储在树图、列表等中。
在这里,我将使用Java Streams:
让我们按其值(升序)对该地图进行排序
Map<String, Integer> mp= new HashMap<>();
mp.put("zebra", 1);
mp.put("blossom", 2);
mp.put("gemini", 3);
mp.put("opera", 7);
mp.put("adelaide", 10);
Map<String, Integer> resultMap= mp.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1, LinkedHashMap::new));
现在,您可以通过多种方式打印排序后的resultMap,例如使用高级for循环或迭代器。
上面的映射也可以按值的降序排序
Map<String, Integer> resultMap= mp.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue().reversed()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1, LinkedHashMap::new));
现在让我们来看另一个场景,我们将“User”存储在地图中,并根据“User”的“name”按升序(词典)对其进行排序:
User u1= new User("hi", 135);
User u2= new User("bismuth", 900);
User u3= new User("alloy", 675);
User u4= new User("jupiter", 342);
User u5= new User("lily", 941);
Map<String, User> map2= new HashMap<>();
map2.put("zebra", u3);
map2.put("blossom", u5);
map2.put("gemini", u1);
map2.put("opera", u2);
map2.put("adelaide", u4);
Map<String, User> resultMap=
map2.entrySet().stream().sorted(Map.Entry.<String, User>comparingByValue( (User o1, User o2)-> o1.getName().compareTo(o2.getName()))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e2, LinkedHashMap::new));
class User
{
String name;
int id;
public User(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User [name=" + name + ", id=" + id + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}