java 字符串排序

字符串排序

需求如下: 给联系人排序, 按照姓名来排序. 要求小写字母排前面,大写字母排后面.

看到这个,我脑海里预想的排序结果是这样的

[aaa,aab,doc,zz,Apple]

也就是说 z 是小于 A 的,在这种需求下.

但是,我看到为手机联系人的排序不是这样的,是a < A < b 的这种效果,而不是之前预期的 a < b < .. < z < A < B .. < Z的这种效果.

当然,具体要什么效果不重要,重要的怎么去实现.

  • 为了装比,我实现的是 a 的这种效果.
java里面默认的字符串排序效果是这样的
before:[abc, ABC, adc, Abc, Abc张三, aa, aBc]
end: [ABC, Abc, Abc张三, aBc, aa, abc, adc]
  • 直接大写字母在前面了,也不是需要的效果. ===> FAILED
java里面忽略大小写的排序效果是这样的
before:[abc, ABC, adc, Abc, Abc张三, aa, aBc]
after: [aa, abc, ABC, Abc, aBc, Abc张三, adc]
  • 其中 ABC 不应该在 Abc的前面,不符合我们的需求. ===> FAILED

我们要的效果是 a

那么,思考一下,这个东西要怎么实现好呢? 按照字符编码, ab之间的 间隔是 1, AB的间隔当然也是 1.

int x = `A` - `B`; // -1
int y = `a` - `b`; // -1
int z = `a` - `A`; // 32

但是现在希望在 a,b之间插入一个 A 进来.

我说一下几个思路,我当时想到的:

  1. 把源字符串转成 26*2 进制的数字, 然后直接比较数字的大小. 比如 "abc" 实际上就成了一个比较大的数字了,具体多少要计算一下,然后全部的字符串都是这样的.

    最后没这么去实现.感觉有点麻烦.而且,如果字符串里面出现了非字母的字符咋办,不知所措.

  2. 放大比较. 既然 ab的间隔只差了1 ,那么将比较结果放大10倍,那么中间就能插入A了. 实际用的就是这种方案

    也想到了遇到非字母的字符要咋办,感觉不用管,在这种实现里面.

具体实现代码不多,但是很有用:

private static class MyComparator
            implements Comparator<String> {

        private static final int FACTOR = 10;
        private static final int DIFF = FACTOR / 2;

        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);
                boolean u1 = Character.isUpperCase(c1);
                boolean u2 = Character.isUpperCase(c2);
                System.out.println(String.format("COMPARE: %s(%s),%s(%s)", s1, c1, s2, c2));
                // A a, A b, A c
                if (c1 != c2) {
                    // No overflow because of numeric promotion
                    if (!u1 && !u2) {
                        int i1 = FACTOR * (c1 - c2);
                        System.err.println(String.format("compare1: %s(%s),%s(%s) ====> %s", s1, c1, s2, c2, i1));
                        return i1;
                    } else if (u1) {
                        // D c == > d+x c   (67 - 66) * 10 + 5            15
                        // D e ==> d+x e (67 - 68) * 10 + 5               -5
                        // D a ==> d+x a (67 - 64) * 10 + 5*1?            35
                        int i1 = FACTOR * (Character.toLowerCase(c1) - c2) + DIFF;
                        System.err.println(String.format("compare2: %s(%s),%s(%s) ====> %s", s1, c1, s2, c2, i1));
                        return i1;
                    } else {
                        // d E == > d e+5 === > d e+x  (67 - 68) * 10 -5        -15
                        // d C ==> d c+5  ===> d c+x  (67 - 66) * 10 -5           5
                        // d A ==> d a+5 ==========>   (67 - 64) * 10 -5         25
                        int i1 = FACTOR * (c1 - Character.toLowerCase(c2)) - DIFF;
                        System.err.println(String.format("compare3: %s(%s),%s(%s) ====> %s", s1, c1, s2, c2, i1));
                        return i1;
                    }
                }
            }
            return n1 - n2;
        }
    }

调用很简单:

List<String> list3 = Arrays.asList("abc", "ABC", "adc", "Abc", "Abc张三", "aa", "aBc");
List<String> strings2 = new ArrayList<>(list3);
System.out.println("BEFORE @@@@@@@@@@@@@@@@@@@@@ : " + strings2);
strings2.sort(new MyComparator());
System.out.println("MyComparator END $$$$$$$$ : " + strings2);

实际输出:

BEFORE @@@@@@@@@@@@@@@@@@@@@ : [abc, ABC, adc, Abc, Abc张三, aa, aBc]
MyComparator END $$$$$$$$ :    [aa, abc, aBc, adc, Abc, Abc张三, ABC]

看到结果了吧,确实实现了 a < A < b < B的效果. ===> PASSED

以上.

你可能感兴趣的:(android,Java)