2019-04-11

2019-04-12  本文已影响0人  从不看女主播的韩超

自然排序和Java中的实现

今天工作中突然遇到一个需求,需要对一个数据集合进行排序,排序的依据是一个字符串字段,由于这个数据集合是利用sql在MySQL中查找的结果,所以很自然而然的想到使用order by语句进行排序

SELECT column1,column2,column3,...
FROM table
WHERE cases
ORDER BY need_sorted_field

正好这种排序结果也满足了客户的需求,所以这个需求也是顺利完成
但是事情远没有那么简单。。。
这种排序机制是建立在字符串的格式完全一致的情况下的,如果不一致,就会出现意想不到的结果,于是我果断查找了资料,发现order by子句的排序算法使用的其实是自然排序(也称字典排序)

自然排序

copy by wiki~~

设想一本英语字典里的单词,哪个在前哪个在后?
显然的做法是先按照第一个字母、以 a、b、c……z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,sigh 和 sight),那么把短者排在前。

不难理解,order by子句就是把要排序的列当成我们平时使用的字典,然后像字典那样去排序

Java中的实现

Java提供了Comparable接口提供给开发者自定义排序策略

public interface Comparable<T> {
    public int compareTo(T o);
}

幸运的是,Java针对字符串也继承了该接口

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;
    }

其实不难发现,这种比较策略大致和sql中的order by的比较策略是基本一样的,因此,以后再面对相同的需求的时候,可以考虑直接使用String类中的排序策略进行排序
除此以外,Java还提供了一种忽略大小写的字符串排序方式,也是实现在String类中

/**
     * 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; }
    }

调用方式很简单

String.CASE_INSENSITIVE_ORDER.compare(str1,str2);//str1和str2为对应的字符串

其实不难发现,这种方式就是在原来的compareTo方法里将字符都转成了大写

参考文献
字典序 by wiki

上一篇下一篇

猜你喜欢

热点阅读