美文网首页
2019-04-11

2019-04-11

作者: 从不看女主播的韩超 | 来源:发表于2019-04-12 00:20 被阅读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

    相关文章

      网友评论

          本文标题:2019-04-11

          本文链接:https://www.haomeiwen.com/subject/uhufwqtx.html