natSort
說明
現(xiàn)實(shí)生活中有很多場景需要用到“自然排序”的算法翰蠢,比如對(duì)金錢表示的排序:“¥165.2橡卤,¥-365.03最盅,¥+0.80”驻右,還比如對(duì)日志文件名稱排序“version1.0.log什黑,version1.1.log1,version01.1.log2”等堪夭。這種情況下使用常規(guī)的字符串排序得到的結(jié)果是與實(shí)際業(yè)務(wù)不符合的愕把,即使查閱了一些第三方的開源框架,也沒有找到很好解決這個(gè)問題的方式(主要是業(yè)務(wù)性比較強(qiáng))森爽,所以不得已自己花了些時(shí)間寫了一個(gè)滿足“自然排序”算法恨豁。
代碼
/**
* <自然排序算法>
* <詳細(xì)介紹>
*
* @author Uncle陽zzZ
* @since 設(shè)計(jì)wiki | 需求wiki
*/
public class NatSortComparator implements Comparator<Object> {
private boolean careCase = false;
private Pattern patternA;
private Pattern patternB;
/**
* careCase
* @param careCase
*/
public NatSortComparator(boolean careCase) {
this.careCase = careCase;
String pattern = "(-|\\+)?\\d+(.\\d+)?"; //^
patternA = Pattern.compile(pattern);
patternB = Pattern.compile(pattern);
}
/**
* 比較算法
* @param a
* @param b
* @return
*/
@Override
public int compare(Object a, Object b) {
// simple compare
if (a == b) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
if (a.equals(b)) {
return 0;
}
String strA = a.toString();
String strB = b.toString();
Matcher matcherA = patternA.matcher(strA);
Matcher matcherB = patternB.matcher(strB);
Map<Integer, Integer> indexMapA = new HashMap<Integer, Integer>();
Map<Integer, Integer> indexMapB = new HashMap<Integer, Integer>();
while (matcherA.find()) {
indexMapA.put(matcherA.start(), matcherA.end());
}
while (matcherB.find()) {
indexMapB.put(matcherB.start(), matcherB.end());
}
int iA = 0;
int iB = 0;
while (true) {
Character cA = getCharacter(strA, iA);
Character cB = getCharacter(strB, iB);
while (isSpaceChar(cA)) {
cA = getCharacter(strA, ++iA);
}
while (isSpaceChar(cB)) {
cB = getCharacter(strB, ++iB);
}
if (indexMapA.containsKey(iA) && indexMapB.containsKey(iB)) {
String tempA = strA.substring(iA, indexMapA.get(iA));
String tempB = strB.substring(iB, indexMapB.get(iB));
int compareResult = Double.compare(Double.parseDouble(tempA), Double.parseDouble(tempB));
if (compareResult != 0) {
return compareResult;
}
iA = indexMapA.get(iA);
iB = indexMapB.get(iB);
continue;
}
if (cA == null && cB == null) {
return 0;
}
if (cA == null) {
return -1;
}
if (cB == null) {
return 1;
}
if (!careCase) {
cA = Character.toUpperCase(cA);
cB = Character.toUpperCase(cB);
}
int tempResult = cA.compareTo(cB);
if (tempResult != 0) {
return tempResult;
}
++iA;
++iB;
}
}
/**
* 獲取字符
* @param var
* @param index
* @return
*/
private Character getCharacter(String var, int index) {
if (var == null || index >= var.length()) {
return null;
}
return var.charAt(index);
}
/**
* 判斷是否是空格
* @param var
* @return
*/
private boolean isSpaceChar(Character var) {
return var != null && Character.isSpaceChar(var);
}
}
問題
由于把‘-’號(hào)和‘+’號(hào)作為了數(shù)字匹配的因素之一,所以在應(yīng)對(duì)諸如時(shí)間格式如“2017-04-25”或者非數(shù)字語義的字符串如“中國-1個(gè)美麗的國度”時(shí),會(huì)出現(xiàn)排序結(jié)果非我所愿的情況∷獯椋看樣子直接通過某一算法來達(dá)到完全智能的排序是不可能的老玛,解決辦法可以針對(duì)不同的業(yè)務(wù)場景來裝配不同的比較器,或者用不同的Wrapper包裝對(duì)象達(dá)到期望的結(jié)果。
github:https://github.com/zhencygo/java/tree/master/algorithm