今天遇到一个关于map排序的问题,做个笔记(__) 嘻嘻……
既然遇到了,就不如挖它祖坟看一看里面的究竟,说不定找到价值连城的古董或者什么的,也说不准,下面,我们就一起带着铲子和摸金校尉,一起去探个究竟吧_
老规矩,先上代码,有代码有真相,如下所示:
/**
*
* Created by zero on 2016-6-11
*
*/
public class HashMapSort
{
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("b", 1 + "");
map.put("cds", 1 + "");
map.put("daac", 23 + "");
map.put("ass", 3 + "");
map.put("daaa", 21 + "");
map.put("f", 2 + "");
map.put("daaz", 25 + "");
map.put("e", 22 + "");
List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(
map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Object>>()
{
public int compare(Entry<String, Object> o1,
Entry<String, Object> o2) {
// // 按key升序排序
return o1.getKey().compareTo(o2.getKey());
// // 按key降序排序
// return o2.getKey().compareTo(o1.getKey());
// // 把value转化成String升序排序
// return ((String) o1.getValue()).compareTo((String) o2.getValue());
// // 把value转化成String降序排序
// return ((String) o2.getValue()).compareTo((String) o1.getValue());
}
});
for (Map.Entry<String, Object> mapping : list)
{
System.out.println(mapping.getKey() + "=" + mapping.getValue());
}
}
}
我们采用的是key的升序排序,执行后的结果是这个样子的
ass=3
b=1
cds=1
daaa=21
daac=23
daaz=25
e=22
f=2
那很多人要说了,我们的产品需要的是降序或者是value排序,那也很简单,只要改return那行代码就好,但是有一点要强调的是,compareTo前后的数据类型要一致,String、Long、Integer等都支持,或者更准确的说,只要实现Comparable接口的都支持,这个接下来会举例分析,现在,我们先看下sort这个函数,在Collections中有两个sort方法,如下所示:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
public static <T> void sort(List<T> list, Comparator<? super T> c) {
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
第一个sort方法,是根据元素的自然顺序对指定列表按升序进行排序。列表中的所有元素都必须实现 Comparable 接口(根据刚刚的介绍,是不是想到了什么?String、Long、Integer等,当然,也可以自己手写去实现接口)。此外,列表中的所有元素都必须是可相互比较的(也就是说,对于列表中的任何 e1 和 e2 元素,e1.compareTo(e2) 不得抛出 ClassCastException)。
此排序方法具有稳定性:不会因调用 sort 方法而对相等的元素进行重新排序。
指定列表必须是可修改的,但不必是大小可调整的。
该排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n log(n) 性能。 此实现将指定列表转储到一个数组中,并对数组进行排序,在重置数组中相应位置处每个元素的列表上进行迭代。这避免了由于试图原地对链接列表进行排序而产生的 n2 log(n)(PS:此处2为平方,忘记平方怎么打了,O(∩_∩)O~) 性能。
我们着重看下第二个sort方法,参数:
·list - 要排序的列表。
·c - 确定列表顺序的比较器。null 值指示应该使用元素的自然顺序。
抛出:
·ClassCastException - 如果列表中包含不可使用指定比较器相互比较 的元素。
·UnsupportedOperationException - 如果指定列表的列表迭代器不支持 set 操作。
根据指定比较器产生的顺序对指定列表进行排序。此列表内的所有元素都必须可使用指定比较器相互比较(也就是说,对于列表中的任意 e1 和 e2 元素,c.compare(e1, e2) 不得抛出 ClassCastException)。
此排序被保证是稳定的:不会因调用 sort 而对相等的元素进行重新排序。
排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n log(n) 性能。 指定列表必须是可修改的,但不必是可大小调整的。此实现将指定列表转储到一个数组中,并对数组进行排序,在重置数组中相应位置每个元素的列表上进行迭代。这避免了由于试图原地对链接列表进行排序而产生的 n2 log(n) 性能。
下面,我们在通过最初代码将Object转换成String,通过value降序排序,就像上述说所得那样,只要打开return就ok,如下:
public class HashMapSort
{
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("b", 1 + "");
map.put("cds", 1 + "");
map.put("daac", 23 + "");
map.put("ass", 3 + "");
map.put("daaa", 21 + "");
map.put("f", 2 + "");
map.put("daaz", 25 + "");
map.put("e", 22 + "");
List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(
map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Object>>()
{
public int compare(Entry<String, Object> o1,
Entry<String, Object> o2) {
// // 按key升序排序
// return o1.getKey().compareTo(o2.getKey());
// // 按key降序排序
// return o2.getKey().compareTo(o1.getKey());
// // 把value转化成String升序排序
// return ((String) o1.getValue()).compareTo((String) o2.getValue());
// // 把value转化成String降序排序
return ((String) o2.getValue()).compareTo((String) o1.getValue());
}
});
for (Map.Entry<String, Object> mapping : list)
{
System.out.println(mapping.getKey() + "=" + mapping.getValue());
}
}
}
运行结果
ass=3
daaz=25
daac=23
e=22
daaa=21
f=2
b=1
cds=1
这个value降序排序是不是有点出乎想象?我们采用的是Object转String,这真的是value降序排序吗?带着这个疑问去打开String源码找到compareTo方法,如下所示:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
..................省略太多代码,只看核心代码.......................
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
}
如果自己打开源码,上面会有一些注释,大致意思是按字典顺序比较两个字符串。该比较基于字符串中各个字符的 Unicode 值。按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。如果这两个字符串相等,则结果为 0;compareTo 只在方法 equals(Object) 返回 true 时才返回 0。
今天的笔记到此为止,一不小心又是凌晨了,这篇只是简单浏览了一遍,没做过多检查,如有错误,欢迎批评指正,好困,睡觉了(~﹃~)~zZ
微信扫我,_
网友评论