หน้าเว็บ

วันอังคารที่ 8 เมษายน พ.ศ. 2557

Multiple points number sorting : java

ผมเชื่อว่าทุกคนเคยเห็นตัวเลขลักษณะนี้  1., 1.1., 6.9.1,  2.5.3, 1.6.1.2, 1.7.3.5 ฯลฯ
มันคือตัวเลขที่เป็น String ซึ่งมีรูปแบบเป็น X.X.X.X (ตัวเลขจะเป็นกี่หลักก็ได้)

ผมขอเรียกว่าตัวเลขแบบนี้ว่า "multiple points number" ก็แล้วกันน่ะครับ
ซึ่งมันไม่สามารถแปลงไปเป็น Float หรือ Double ได้ (เพราะมันเป็น single point)

ปัญหา
ถ้าเราเขียน code การจัดเรียง String แบบธรรมดาๆ เราจะได้ผลลัพธ์การจัดเรียงที่ไม่ถูกต้อง ดังรูป
จะเห็นว่า 10. กับ 11. มาก่อน 2. เนื่องจาก มันจัดเรียงตามหลักพจนานุกรมครับ  ไม่ได้เอาค่าของตัวเลขจริงๆ มาคิด


จากตัวอย่างรูปข้างบน  code ที่เราเขียนจะเป็นลักษณะนี้  ซึ่งมัน "ผิด"
Collections.sort(children, new Comparator<TreeModel>() {

    @Override
    public int compare(TreeModel model1, TreeModel model2) {
        return model1.getId().compareTo(model2.getId()); /***/
    }
});

เราอาจจะแปลงมันไปเป็น Float หรือ Double ก่อน ก็ไม่ได้น่ะครับ  เนื่องจากมันเป็น multiple points ไม่ใช่ตัวเลขที่เป็นทศนิยม (single point) มันจะ throw Exception ออกมาครับ

วิธีแก้
เขียน code สำหรับจัดเรียงขึ้นมาใหม่ ดังนี้
MultiplePointsNumberSorting.java
package com.blogspot.na5cent.util;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 *
 * @author redcrow
 */
public class MultiplePointsNumberSorting {

    public static List<String> sort(List<String> numbers) {

        Collections.sort(numbers, new Comparator<String>() {

            @Override
            public int compare(String s1, String s2) {
                return compare(s1, s2); 
            }
        });

        return numbers;
    }

    public static int compare(String str1, String str2) {
        // ทำการแยกตัวเลข  ออกจากจุด "." เช่น 3.1.2.4 --> {"3", "1", "2", "4"}
        // สัญลักษณ์ \\. เป็น regular expression
        String[] split1 = str1.split("\\."); 
        String[] split2 = str2.split("\\.");

        // เลือกหลักตัวเลขที่มีค่าสูงสุด เช่น 1.2 กับ 1.5.2.3
        // ค่าที่ได้จะเป็น 4 
        int length = (split1.length > split2.length) ? split1.length : split2.length;

        // วน loop เปรียบเทียบค่าทีละหลัก 
        for (int i = 0; i < length; i++) {
            int numb1;
            try {
                // แปลง string ไปเป็นตัวเลขก่อน
                numb1 = Integer.parseInt(split1[i]); 
            } catch (Exception ex) {
                // numb1 < numb2 
                // ซึ่งอาจเกิดจากสาเหตุ numb1 มีจำนวนหลักตัวเลขน้อยกว่า numb2 
                // แต่ตอน loop เรา loop ตาม จำนวนหลักของ numb2 (เกิด ArrayIndexOutOfBoundsException)
                // หรือ numb1 มีรูปแบบตัวเลขที่ไม่ถูกต้อง  (NumberFormatException)
                return -1; 
            }

            int numb2;
            try {
                numb2 = Integer.parseInt(split2[i]);
            } catch (Exception ex) {
                // คล้าย numb1 แต่อันนี้หมายความว่า numb1 > numb2
                return 1; 
            }

            if (numb1 > numb2) {
                return 1;
            }

            if (numb1 < numb2) {
                return -1;
            }
        }

        return 0; //numb1 เท่ากับ numb2
    }
}
วิธีใช้
ปรับปรุงจาก code เดิมก่อนหน้านี้
Collections.sort(children, new Comparator<TreeModel>() {

    @Override
    public int compare(TreeModel model1, TreeModel model2) {
        return MultiplePointsNumberSorting.compare(model1.getId(), model2.getId()); /*****/
    }
});

"เราสามารถเอาไปประยุกต์ใช้กับการจัดเรียง IP address ได้ครับ"
เนื่องจากมันมีลักษณะเป็น X.X.X.X เหมือนกัน

ไม่มีความคิดเห็น:

แสดงความคิดเห็น