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);
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章