自然排序和Java中的實(shí)現(xiàn)
今天工作中突然遇到一個(gè)需求,需要對(duì)一個(gè)數(shù)據(jù)集合進(jìn)行排序罐栈,排序的依據(jù)是一個(gè)字符串字段豪嗽,由于這個(gè)數(shù)據(jù)集合是利用sql在MySQL中查找的結(jié)果,所以很自然而然的想到使用order by語(yǔ)句進(jìn)行排序
SELECT column1,column2,column3,...
FROM table
WHERE cases
ORDER BY need_sorted_field
正好這種排序結(jié)果也滿(mǎn)足了客戶(hù)的需求冕象,所以這個(gè)需求也是順利完成
但是事情遠(yuǎn)沒(méi)有那么簡(jiǎn)單代承。。渐扮。
這種排序機(jī)制是建立在字符串的格式完全一致的情況下的论悴,如果不一致,就會(huì)出現(xiàn)意想不到的結(jié)果墓律,于是我果斷查找了資料膀估,發(fā)現(xiàn)order by子句的排序算法使用的其實(shí)是自然排序(也稱(chēng)字典排序)
自然排序
copy by wiki~~
設(shè)想一本英語(yǔ)字典里的單詞,哪個(gè)在前哪個(gè)在后耻讽?
顯然的做法是先按照第一個(gè)字母察纯、以 a、b针肥、c……z 的順序排列饼记;如果第一個(gè)字母一樣,那么比較第二個(gè)慰枕、第三個(gè)乃至后面的字母具则。如果比到最后兩個(gè)單詞不一樣長(zhǎng)(比如,sigh 和 sight)捺僻,那么把短者排在前乡洼。
不難理解,order by子句就是把要排序的列當(dāng)成我們平時(shí)使用的字典匕坯,然后像字典那樣去排序
Java中的實(shí)現(xiàn)
Java提供了Comparable
接口提供給開(kāi)發(fā)者自定義排序策略
public interface Comparable<T> {
public int compareTo(T o);
}
幸運(yùn)的是束昵,Java針對(duì)字符串也繼承了該接口
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
并且提供了簡(jiǎn)單的排序算法
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;
}
其實(shí)不難發(fā)現(xiàn),這種比較策略大致和sql中的order by的比較策略是基本一樣的葛峻,因此锹雏,以后再面對(duì)相同的需求的時(shí)候,可以考慮直接使用String
類(lèi)中的排序策略進(jìn)行排序
除此以外术奖,Java還提供了一種忽略大小寫(xiě)的字符串排序方式礁遵,也是實(shí)現(xiàn)在String
類(lèi)中
/**
* A Comparator that orders {@code String} objects as by
* {@code compareToIgnoreCase}. This comparator is serializable.
* <p>
* Note that this Comparator does <em>not</em> take locale into account,
* and will result in an unsatisfactory ordering for certain locales.
* The java.text package provides <em>Collators</em> to allow
* locale-sensitive ordering.
*
* @see java.text.Collator#compare(String, String)
* @since 1.2
*/
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
/** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
調(diào)用方式很簡(jiǎn)單
String.CASE_INSENSITIVE_ORDER.compare(str1,str2);//str1和str2為對(duì)應(yīng)的字符串
其實(shí)不難發(fā)現(xiàn),這種方式就是在原來(lái)的compareTo
方法里將字符都轉(zhuǎn)成了大寫(xiě)
參考文獻(xiàn)
字典序 by wiki