BUG集锦--国家区号按照首字母排序分组

写在前头

记录一个有意思的事情。有意思的在后记。

APP端要实现下图效果,选择国家地区的时候,要把数据进行排序分组,返回给客户端。
在这里插入图片描述

解决思路

为了提高客户端响应速度,把数据排序分组做在了后台,在数据库里面就存每个国家的首字母,用来作为排序分组的分组条件;虽然前期维护数据的工作量较大,但很多处理逻辑就都省略了;

第一步,将需要数据按照首字母升序,查出数据列表;

第二步,定义一个Map,key为A~Z,value是List;循环字母表和数据列表,若数据列表中首字母字段和key相等,则将该记录添加到对应key的list中;

代码如下:

   StringBuffer sb = new StringBuffer();
       
        if (LanguageType.CHINESE.equals(locationRequestVO.getLanguage())) {
            sb.append("select name,id,pid,start_letter as startLetter from tbl_location where  pid='"+locationRequestVO.getPid()+"' ORDER BY start_letter asc  ");
        } else {        
            sb.append("select name_en as name,id,pid,start_letter_en as startLetter from tbl_location where  pid='"+locationRequestVO.getPid()+"'  ORDER BY start_letter_en asc  ");
        }
       
        List<LocationResponseVO> list = this.findMapBySql(sb.toString(),new Object[]{},new Type[]{},LocationResponseVO.class);

        // 以上部分是获取数据列表,方式不一,可以忽略;
        
        // 分组给前台返回,这是重点。
        Map<String, List<Object>> map = new LinkedHashMap<>();
        
        String word = "";
        
        for (int i = 1; i <= 26; i++) {
            boolean ifShowLetter = true;
            word = String.valueOf((char) (96 + i)).toUpperCase();
            map.put(word,new ArrayList<>());
            for (int j = 0; j < list.size(); j++) {
                if (word.equals(list.get(j).getStartLetter())) {
                    map.get(word).add(list.get(j));
                    // 看出点什么没?
                    list.remove(list.get(j));
                    ifShowLetter = false;
                }
            }
            if(ifShowLetter){
                map.remove(word);
            }
        }
        return success(map);

有点意思

  1. word = String.valueOf((char) (96 + i)).toUpperCase();

ASCII字符编码表中,使用97-122 的ASCII值控制字符a-z,这里用来定义Map中的key,当然了自己定义26个字母数组也是可以的;

  1. list.remove(list.get(j));

为啥要删呢?这条记录,已经被添加了,删除过后,list长度变短,下次循环时间减少。

  1. LinkedHashMap

LinkedHashMap底层是使用链表进行存储,而HashMap 是随机插入的,客户端拿到数据后,直接显示就行。

  1. ifShowLetter

布尔变量值,当没有相应key的value时,就把key也去掉,这样客户端拿到数据就不会有一些空数据了;

  1. mysql获取汉字转拼音

数据维护首字母的时候,我看了一下数据库这张表结构,为了获取首字母,先要将中文转为拼音。参考链接:mysql获取汉字拼音
在这里插入图片描述

一、创建拼音对照表

-- 创建汉字拼音对照临时表
CREATE TABLE IF NOT EXISTS `t_base_pinyin` (
  `pin_yin_` varchar(255) CHARACTER SET gbk NOT NULL,
  `code_` int(11) NOT NULL,
  PRIMARY KEY (`code_`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

二、插入对照数据

-- 插入数据
INSERT INTO t_base_pinyin (pin_yin_,code_)  VALUES ("a", 20319),("ai", 20317),("an", 20304),("ang", 20295),("ao", 20292),("ba", 20283),("bai", 20265),("ban", 20257),("bang", 20242),("bao", 20230),("bei", 20051),("ben", 20036),("beng", 20032),("bi", 20026),("bian", 20002),("biao", 19990),("bie", 19986),("bin", 19982),("bing", 19976),("bo", 19805),("bu", 19784),("ca", 19775),("cai", 19774),("can", 19763),("cang", 19756),("cao", 19751),("ce", 19746),("ceng", 19741),("cha", 19739),("chai", 19728),("chan", 19725),("chang", 19715),("chao", 19540),("che", 19531),("chen", 19525),("cheng", 19515),("chi", 19500),("chong", 19484),("chou", 19479),("chu", 19467),("chuai", 19289),("chuan", 19288),("chuang", 19281),("chui", 19275),("chun", 19270),("chuo", 19263),("ci", 19261),("cong", 19249),("cou", 19243),("cu", 19242),("cuan", 19238),("cui", 19235),("cun", 19227),("cuo", 19224),("da", 19218),("dai", 19212),("dan", 19038),("dang", 19023),("dao", 19018),("de", 19006),("deng", 19003),("di", 18996),("dian", 18977),("diao", 18961),("die", 18952),("ding", 18783),("diu", 18774),("dong", 18773),("dou", 18763),("du", 18756),("duan", 18741),("dui", 18735),("dun", 18731),("duo", 18722),("e", 18710),("en", 18697),("er", 18696),("fa", 18526),("fan", 18518),("fang", 18501),("fei", 18490),("fen", 18478),("feng", 18463),("fo", 18448),("fou", 18447),("fu", 18446),("ga", 18239),("gai", 18237),("gan", 18231),("gang", 18220),("gao", 18211),("ge", 18201),("gei", 18184),("gen", 18183),("geng", 18181),("gong", 18012),("gou", 17997),("gu", 17988),("gua", 17970),("guai", 17964),("guan", 17961),("guang", 17950),("gui", 17947),("gun", 17931),("guo", 17928),("ha", 17922),("hai", 17759),("han", 17752),("hang", 17733),("hao", 17730),("he", 17721),("hei", 17703),("hen", 17701),("heng", 17697),("hong", 17692),("hou", 17683),("hu", 17676),("hua", 17496),("huai", 17487),("huan", 17482),("huang", 17468),("hui", 17454),("hun", 17433),("huo", 17427),("ji", 17417),("jia", 17202),("jian", 17185),("jiang", 16983),("jiao", 16970),("jie", 16942),("jin", 16915),("jing", 16733),("jiong", 16708),("jiu", 16706),("ju", 16689),("juan", 16664),("jue", 16657),("jun", 16647),("ka", 16474),("kai", 16470),("kan", 16465),("kang", 16459),("kao", 16452),("ke", 16448),("ken", 16433),("keng", 16429),("kong", 16427),("kou", 16423),("ku", 16419),("kua", 16412),("kuai", 16407),("kuan", 16403),("kuang", 16401),("kui", 16393),("kun", 16220),("kuo", 16216),("la", 16212),("lai", 16205),("lan", 16202),("lang", 16187),("lao", 16180),("le", 16171),("lei", 16169),("leng", 16158),("li", 16155),("lia", 15959),("lian", 15958),("liang", 15944),("liao", 15933),("lie", 15920),("lin", 15915),("ling", 15903),("liu", 15889),("long", 15878),("lou", 15707),("lu", 15701),("lv", 15681),("luan", 15667),("lue", 15661),("lun", 15659),("luo", 15652),("ma", 15640),("mai", 15631),("man", 15625),("mang", 15454),("mao", 15448),("me", 15436),("mei", 15435),("men", 15419),("meng", 15416),("mi", 15408),("mian", 15394),("miao", 15385),("mie", 15377),("min", 15375),("ming", 15369),("miu", 15363),("mo", 15362),("mou", 15183),("mu", 15180),("na", 15165),("nai", 15158),("nan", 15153),("nang", 15150),("nao", 15149),("ne", 15144),("nei", 15143),("nen", 15141),("neng", 15140),("ni", 15139),("nian", 15128),("niang", 15121),("niao", 15119),("nie", 15117),("nin", 15110),("ning", 15109),("niu", 14941),("nong", 14937),("nu", 14933),("nv", 14930),("nuan", 14929),("nue", 14928),("nuo", 14926),("o", 14922),("ou", 14921),("pa", 14914),("pai", 14908),("pan", 14902),("pang", 14894),("pao", 14889),("pei", 14882),("pen", 14873),("peng", 14871),("pi", 14857),("pian", 14678),("piao", 14674),("pie", 14670),("pin", 14668),("ping", 14663),("po", 14654),("pu", 14645),("qi", 14630),("qia", 14594),("qian", 14429),("qiang", 14407),("qiao", 14399),("qie", 14384),("qin", 14379),("qing", 14368),("qiong", 14355),("qiu", 14353),("qu", 14345),("quan", 14170),("que", 14159),("qun", 14151),("ran", 14149),("rang", 14145),("rao", 14140),("re", 14137),("ren", 14135),("reng", 14125),("ri", 14123),("rong", 14122),("rou", 14112),("ru", 14109),("ruan", 14099),("rui", 14097),("run", 14094),("ruo", 14092),("sa", 14090),("sai", 14087),("san", 14083),("sang", 13917),("sao", 13914),("se", 13910),("sen", 13907),("seng", 13906),("sha", 13905),("shai", 13896),("shan", 13894),("shang", 13878),("shao", 13870),("she", 13859),("shen", 13847),("sheng", 13831),("shi", 13658),("shou", 13611),("shu", 13601),("shua", 13406),("shuai", 13404),("shuan", 13400),("shuang", 13398),("shui", 13395),("shun", 13391),("shuo", 13387),("si", 13383),("song", 13367),("sou", 13359),("su", 13356),("suan", 13343),("sui", 13340),("sun", 13329),("suo", 13326),("ta", 13318),("tai", 13147),("tan", 13138),("tang", 13120),("tao", 13107),("te", 13096),("teng", 13095),("ti", 13091),("tian", 13076),("tiao", 13068),("tie", 13063),("ting", 13060),("tong", 12888),("tou", 12875),("tu", 12871),("tuan", 12860) ,("tui", 12858),("tun", 12852),("tuo", 12849),("wa", 12838),("wai", 12831),("wan", 12829),("wang", 12812),("wei", 12802),("wen", 12607),("weng", 12597),("wo", 12594),("wu", 12585),("xi", 12556),("xia", 12359),("xian", 12346),("xiang", 12320),("xiao", 12300),("xie", 12120),("xin", 12099),("xing", 12089),("xiong", 12074),("xiu", 12067),("xu", 12058),("xuan", 12039),("xue", 11867),("xun", 11861),("ya", 11847),("yan", 11831),("yang", 11798),("yao", 11781),("ye", 11604),("yi", 11589),("yin", 11536),("ying", 11358),("yo", 11340),("yong", 11339),("you", 11324),("yu", 11303),("yuan", 11097),("yue", 11077),("yun", 11067),("za", 11055),("zai", 11052),("zan", 11045),("zang", 11041),("zao", 11038),("ze", 11024),("zei", 11020),("zen", 11019),("zeng", 11018),("zha", 11014),("zhai", 10838),("zhan", 10832),("zhang", 10815),("zhao", 10800),("zhe", 10790),("zhen", 10780),("zheng", 10764),("zhi", 10587),("zhong", 10544),("zhou", 10533),("zhu", 10519),("zhua", 10331),("zhuai", 10329),("zhuan", 10328),("zhuang", 10322),("zhui", 10315),("zhun", 10309),("zhuo", 10307),("zi", 10296),("zong", 10281),("zou", 10274),("zu", 10270),("zuan", 10262),("zui", 10260),("zun", 10256),("zuo", 10254);

三、创建函数汉字转拼音

-- 建立汉字转换拼音函数
DROP FUNCTION IF EXISTS to_pinyin;
DELIMITER $
CREATE FUNCTION to_pinyin(NAME VARCHAR(255) CHARSET gbk)
RETURNS VARCHAR(255) CHARSET gbk
BEGIN
    DECLARE mycode INT;
    DECLARE tmp_lcode VARCHAR(2) CHARSET gbk;
    DECLARE lcode INT;

    DECLARE tmp_rcode VARCHAR(2) CHARSET gbk;
    DECLARE rcode INT;

    DECLARE mypy VARCHAR(255) CHARSET gbk DEFAULT '';
    DECLARE lp INT;

    SET mycode = 0;
    SET lp = 1;

    SET NAME = HEX(NAME);

    WHILE lp < LENGTH(NAME) DO

        SET tmp_lcode = SUBSTRING(NAME, lp, 2);
        SET lcode = CAST(ASCII(UNHEX(tmp_lcode)) AS UNSIGNED);
        SET tmp_rcode = SUBSTRING(NAME, lp + 2, 2);
        SET rcode = CAST(ASCII(UNHEX(tmp_rcode)) AS UNSIGNED);
        IF lcode > 128 THEN
            SET mycode =65536 - lcode * 256 - rcode ;
            SELECT CONCAT(mypy,pin_yin_) INTO mypy FROM t_base_pinyin WHERE CODE_ >= ABS(mycode) ORDER BY CODE_ ASC LIMIT 1;
            SET lp = lp + 4;
        ELSE
            SET mypy = CONCAT(mypy,CHAR(CAST(ASCII(UNHEX(SUBSTRING(NAME, lp, 2))) AS UNSIGNED)));
            SET lp = lp + 2;
        END IF;
    END WHILE;
    RETURN LOWER(mypy);
END;
$
DELIMITER ;

四、使用函数

-- 中文名字转拼音
update tbl_location
set name_pinyin = to_pinyin(name)

-- 取拼音第一个字符,设置为首字母
update tbl_location
set start_letter_en = UPPER(SUBSTR(name_en FROM 1 FOR 1))

以上方法解决了我的问题,但按照首字母分组排序,获取数据,上面双重for循环的算法,不是最优的;也是可以优化的。

欢迎大家留言指正。

11.08后记

本来写在前头的就是件有意思的事情,今天测试发现了这么个事情,看图说话
数据库里以“A”开头的国家有17个,

在这里插入图片描述
而客户端显示只有6个
在这里插入图片描述
这是为啥,找原因吧。

最后终于是找到了,错误出在了list.remove(list.get(j));

这行代码,本来是想既然list的某个元素已经被选择了,下次循环就不必要再去和它比较了,但却忘记了,j的值却没有从0开始。

如图,当word为“A”时,list.get(0) 是“阿塞拜疆”,符合word=“A”;将其从list中删除;list–>New List
在这里插入图片描述
这是,j从0->1,在new List中,获取list.get(1),是阿尔及利亚,跳过了阿富汗;从而导致了漏掉数据的结果;

解决这个问题,也很简单,可以不删除元素;也可以在删除元素后,将j的值赋值为0;

因为从数据库中取出的数据是排过序的,所以我选择了j赋值为0,最终分组排序代码:

  // 分组给前台返回
        Map<String, List<Object>> map = new LinkedHashMap<>();
        String word = "";
        for (int i = 1; i <= 26; i++) {
            boolean ifShowLetter = true;
            word = String.valueOf((char) (96 + i)).toUpperCase();
            map.put(word, new ArrayList<>());
            for (int j = 0; j < list.size(); j++) {
                  if (word.equals(list.get(j).getStartLetter())) {
                    map.get(word).add(list.get(j));
                    list.remove(list.get(j));
                    j= 0;
                    ifShowLetter = false;
                }
            }
            if (ifShowLetter) {
                map.remove(word);
            }

更有意思的来了,在老友东(大神,推给你)的建议下,去掉双重for循环,丢掉ifShowLetter 标识,因为最终的目的是库里有什么首字母,map里就存什么;调用了map的containsKey()方法了;

忽略了 map的好方法,最终优化的版本:

  // 分组给前台返回
        Map<String, List<Object>> map = new LinkedHashMap<>();
        for(LocationResponseVO o :list){
            if(!map.containsKey(o.getStartLetter())){
                map.put(o.getStartLetter(),new ArrayList<>());
            }
            map.get(o.getStartLetter()).add(o);
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章