java List Map String Object泛型通用排序 支持两个字段排序

环境

java:1.7+

前言

公司有个公共的排序方法类,其中,字符串一个方法、日期字符串一个方法、数字一个方法等等;
我觉得这些方法都可以写成一个方法;

下面代码只针对List<Map<String, Object>>这种方式进行排序

代码

完整代码
下面这段代码有问题 继续看后面的优化代码

/**
 * 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
 * @param result 结果集
 * @param order
 * @param orderType -1降序 1升序, 下面代码假设orderType为1
 * @return
 * @author yutao
 * @date 2018年4月24日下午2:20:35
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){

    if(result == null || orderType == null){
        return result;
    }

    if(orderType != -1){
        orderType = 1;
    }

    final String orderKey = order;
    final Integer oType = orderType;

    Collections.sort(result, new Comparator<Map<String, Object>>() {

        @Override
        public int compare(Map<String, Object> o1, Map<String, Object> o2) {
            Object obj1 = o1.get(orderKey);
            Object obj2 = o2.get(orderKey);

            if (obj1 == null) {
                if(oType < 0){
                    return -oType;
                }
                return oType;
            }
            if (obj2 == null) {
                if(oType < 0){
                    return oType;
                }
                return -oType;
            }

            if(obj1 instanceof Date){
                //日期排序
                Date date1 = (Date)obj1;
                Date date2 = (Date)obj2;
                return longCompare(oType, date1.getTime(), date2.getTime());
            }else if(obj1 instanceof String){
                //字符串排序
                String str1 = obj1.toString();
                String str2 = obj2.toString();

                if(str1.compareTo(str2) < 0){
                    return -oType;
                }else if(str1.compareTo(str2) == 0){
                    return 0;
                }else if(str1.compareTo(str2) > 0){
                    return oType;
                }
            }else if(obj1 instanceof Double || obj1 instanceof Float){
                //浮点型排序
                return doubleCompare(oType, obj1, obj2);
            }else if(obj1 instanceof Long || obj1 instanceof Integer || obj1 instanceof Short || obj1 instanceof Byte){
                //整数型排序
                return longCompare(oType, obj1, obj2);
            }
            return 0;
        }
    });
    return result;
}

private static int longCompare(final Integer oType, Object obj1, Object obj2) {
    long d1 = Long.parseLong(obj1.toString());
    long d2 = Long.parseLong(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        //相同的是否进行交互
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

private static int doubleCompare(final Integer oType, Object obj1, Object obj2) {
    double d1 = Double.parseDouble(obj1.toString());
    double d2 = Double.parseDouble(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

讲解:
Collections.sort()的排序规则参考:
https://blog.csdn.net/u013066244/article/details/78997869
② 如果是字符串就用compareTo方法进行比较;
如果是整数(各种整数)或者Date,都统一转成long进行比较。
如果是浮点数,就转成Double进行比较。

犯的错误

long d1 = Long.parseLong(obj1.toString());
long d2 = Long.parseLong(obj2.toString());

//错误写法
Long d1 = Long.valueOf(obj1.toString());
Long d2 = Long.valueOf(obj2.toString());
//当为Integer或者其他非Long整数时,会报类型转换异常

相同元素不交换带来的后果

上面的代码中,如果元素相同,不会进行交互,那么在进行倒序时可能会与实际想要的结果有偏差。

比如:
假设数据库降序的顺序如下,按照count的值进行排序:

{
    name: "a",
    count: 29
},
{
    name: "b",
    count: 22
},
{
    name: "c",
    count: 22
}

我们再使用上面的代码,在内存里进行倒序(即升序)。
结果为:

{
    name: "b",
    count: 22
},
{
    name: "c",
    count: 22
},
{   name: "a",
    count: 29
}

但是可能我们实际想要的结果应该为

{
    name: "c",
    count: 22
},
{
    name: "b",
    count: 22
},
{   name: "a",
    count: 29
}

为什么结果会这样呢?因为b和a进行比较count时,a大,排后面,接下来b和c进行比较,发现相同,上面的代码返回0,也就是不交换,这时,c就放b的后头,因为算法认为,目前b才是最小的。

针对这样的情况,我们反而希望,相同时,发生交换。

总结

内存排序,不到万不得已才去用,一般数据库排序是最好的!

当需要内存排序时,相同元素是否发生交换需要而外注意。

==============2018-05-18======================start=======
今天遇到这样一个错误:

java.lang.NumberFormatException: For input string: \"0.002091696324526065\"

之所以会报这个错误,是因为其执行到了longCompare()这个方法,也就是当做整型来处理。
为什么呢?通过打日志我知道了:

class java.lang.Integer---------该值为-------0
class java.lang.Double---------该值为--------0.035

我的数据中,既有Integer型,又有Double型,而我上面的代码判断,只判断Obj1,这样在执行时,就会把两个元素都当做整型来处理。所以就调了longCompare()方法。这块需要优化

优化后的代码

/**
 * 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
 * @param result 结果集
 * @param order
 * @param orderType -1降序 1升序, 下面代码假设orderType为1
 * @return
 * @author yutao
 * @date 2018年4月24日下午2:20:35
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){

    if(result == null || orderType == null){
        return result;
    }

    if(orderType != -1){
        orderType = 1;
    }

    final String orderKey = order;
    final Integer oType = orderType;

    Collections.sort(result, new Comparator<Map<String, Object>>() {

        @Override
        public int compare(Map<String, Object> o1, Map<String, Object> o2) {
            Object obj1 = o1.get(orderKey);
            Object obj2 = o2.get(orderKey);

            if (obj1 == null) {
                if(oType < 0){
                    return -oType;
                }
                return oType;
            }
            if (obj2 == null) {
                if(oType < 0){
                    return oType;
                }
                return -oType;
            }

            if(obj1 instanceof Date && obj2 instanceof Date){
                //日期排序
                Date date1 = (Date)obj1;
                Date date2 = (Date)obj2;
                return longCompare(oType, date1.getTime(), date2.getTime());
            }else if(obj1 instanceof String && obj2 instanceof String){
                //字符串排序
                String str1 = obj1.toString();
                String str2 = obj2.toString();

                if(str1.compareTo(str2) < 0){
                    return -oType;
                }else if(str1.compareTo(str2) == 0){
                    return 0;
                }else if(str1.compareTo(str2) > 0){
                    return oType;
                }
            }else if((obj1 instanceof Double || obj1 instanceof Float) && (obj2 instanceof Double || obj2 instanceof Float)){
                //浮点型排序
                return doubleCompare(oType, obj1, obj2);
            }else if((obj1 instanceof Long || obj1 instanceof Integer || obj1 instanceof Short || obj1 instanceof Byte) && 
                     (obj2 instanceof Long || obj2 instanceof Integer || obj2 instanceof Short || obj2 instanceof Byte)){
                //整数型排序
                return longCompare(oType, obj1, obj2);
            }else if((obj1.getClass() != obj2.getClass()) && (obj1 instanceof Number && obj2 instanceof Number)){
                //这种情况可能是,既有整数又有浮点数
                return doubleCompare(oType, obj1, obj2);
            }
            return 0;
        }
    });
    return result;
}

private static int longCompare(final Integer oType, Object obj1, Object obj2) {
    long d1 = Long.parseLong(obj1.toString());
    long d2 = Long.parseLong(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        //相同的是否进行交互
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

private static int doubleCompare(final Integer oType, Object obj1, Object obj2) {
    double d1 = Double.parseDouble(obj1.toString());
    double d2 = Double.parseDouble(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

其实上面的代码应该还可以优化,就是无论是整数还是浮点数,都当做Double来处理。

遇到的异常

Comparison method violates its general contract!

因为我的代码里没有return

... 上面代码省略。。。
else if((obj1.getClass() != obj2.getClass()) && 
(obj1 instanceof Number && obj2 instanceof Number)){
                //这种情况可能是,既有整数又有浮点数
                 doubleCompare(oType, obj1, obj2);//我这里没有写return 也就是自定义排序,不给任何数字
            }

==============2018-05-18======================end=======

==============2018-05-24======================start=======

两个字段排序

今天需要一个需求,是要两个字段进行排序,所以我得进行以下修改;

思路:既然是两个字段排序,那么我们就要先第一字段排好序后,相等的话,再进行第二字段排序。

直接上完整的代码了:

/**
 * 支持两个字段排序
 * @param result
 * @param order
 * @param orderType
 * @param twoOrder 第二排序字段
 * @param twoType 第二排序顺序
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:00:03
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType, 
                                                    final String twoOrder, final Integer twoType){

    if(result == null || orderType == null){
        return result;
    }

    if(orderType != -1){
        orderType = 1;
    }

    final String orderKey = order;
    final Integer oType = orderType;

    Collections.sort(result, new Comparator<Map<String, Object>>() {
        @Override
        public int compare(Map<String, Object> o1, Map<String, Object> o2) {
            Object obj1 = o1.get(orderKey);
            Object obj2 = o2.get(orderKey);
            return commonOrder(orderKey, oType, obj1, obj2, twoOrder, twoType);
        }
    });
    return result;
}

/**
 * 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
 * @param result 结果集
 * @param order
 * @param orderType -1降序 1升序, 下面代码假设orderType为1
 * @return
 * @author yutao
 * @date 2018年4月24日下午2:20:35
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){
    return resultOrder(result, order, orderType, null, null);
}

/**
 * 公共的排序部分
 * @param orderKey
 * @param oType
 * @param obj1
 * @param obj2
 * @param twoOrder
 * @param twoType
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:19:37
 */
public static Integer commonOrder(final String orderKey, final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    if (obj1 == null) {
        if(oType < 0){
            return -oType;
        }
        return oType;
    }
    if (obj2 == null) {
        if(oType < 0){
            return oType;
        }
        return -oType;
    }

    if(obj1 instanceof Date && obj2 instanceof Date){
        //日期排序
        Date date1 = (Date)obj1;
        Date date2 = (Date)obj2;
        return longCompare(oType, date1.getTime(), date2.getTime(), twoOrder, twoType);
    }else if(obj1 instanceof String && obj2 instanceof String){
        //字符串排序
        String str1 = obj1.toString();
        String str2 = obj2.toString();

        if(str1.compareTo(str2) < 0){
            return -oType;
        }else if(str1.compareTo(str2) == 0){
            return 0;
        }else if(str1.compareTo(str2) > 0){
            return oType;
        }
    }else if((obj1 instanceof Double || obj1 instanceof Float) && (obj2 instanceof Double || obj2 instanceof Float)){
        //浮点型排序
        return doubleCompare(oType, obj1, obj2, twoOrder, twoType);
    }else if((obj1 instanceof Long || obj1 instanceof Integer || obj1 instanceof Short || obj1 instanceof Byte) && 
             (obj2 instanceof Long || obj2 instanceof Integer || obj2 instanceof Short || obj2 instanceof Byte)){
        //整数型排序
        return longCompare(oType, obj1, obj2, twoOrder, twoType);
    }else if((obj1.getClass() != obj2.getClass()) && (obj1 instanceof Number && obj2 instanceof Number)){
        //这种情况可能是,既有整数又有浮点数
        return doubleCompare(oType, obj1, obj2, twoOrder, twoType);
    }
    return 0;
}


/**
 * 整形比较大小
 * @param oType
 * @param obj1
 * @param obj2
 * @param twoOrder
 * @param twoType
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:09:18
 */
private static int longCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    long d1 = Long.parseLong(obj1.toString());
    long d2 = Long.parseLong(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){

        if(twoOrder != null && twoType != null){
            //相等就使用第二字段排序
            return commonOrder(twoOrder, twoType, obj1, obj2, null, null);
        }
        //相同的是否进行交互
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

/**
 * 浮点型比较大小
 * @param oType
 * @param obj1
 * @param obj2
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:09:41
 */
private static int doubleCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    double d1 = Double.parseDouble(obj1.toString());
    double d2 = Double.parseDouble(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        if(twoOrder != null && twoType != null){

            //相等就使用第二字段排序
            return commonOrder(twoOrder, twoType, obj1, obj2, null, null);
        }
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

==============2018-05-24======================end=======

==============2018-05-31======================start=======

上面的代码其实并不能实现两个字段排序,逻辑上有点问题。

因为第二次,并没有改变排序字段obj1|obj2

/**
 * 支持两个字段排序
 * @param result
 * @param order
 * @param orderType
 * @param twoOrder 第二排序字段
 * @param twoType 第二排序顺序
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:00:03
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType, 
                                                    final String twoOrder, final Integer twoType){

    if(result == null || orderType == null){
        return result;
    }

    if(orderType != -1){
        orderType = 1;
    }

    final String orderKey = order;
    final Integer oType = orderType;

    Collections.sort(result, new Comparator<Map<String, Object>>() {
        @Override
        public int compare(Map<String, Object> o1, Map<String, Object> o2) {
            //这里加了个判空,原则上,空元素(map)就不该进来
            if(o1 == null && o2 == null){
                return 0;
            }
            if (o1 == null) {
                if(oType < 0){
                    return -oType;
                }
                return oType;
            }
            if (o2 == null) {
                if(oType < 0){
                    return oType;
                }
                return -oType;
            }
            return commonOrder(orderKey, oType, obj1, obj2, twoOrder, twoType, o1, o2);
        }
    });
    return result;
}


/**
 * 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
 * @param result 结果集
 * @param order
 * @param orderType -1降序 1升序, 下面代码假设orderType为1
 * @return
 * @author yutao
 * @date 2018年4月24日下午2:20:35
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){
    return resultOrder(result, order, orderType, null, null);
}

/**
 * 公共的排序部分
 * @param orderKey
 * @param oType
 * @param obj1
 * @param obj2
 * @param twoOrder
 * @param twoType
 * @return
 * @author yutao
 * @param obj2 
 * @param obj1 
 * @param o2 
 * @param o1 
 * @date 2018年5月24日下午3:19:37
 */
public static Integer commonOrder(final String orderKey, final Integer oType, String twoOrder, Integer twoType, 
        Map<String, Object> o1, Map<String, Object> o2) {
    Object obj1 = o1.get(orderKey);
    Object obj2 = o2.get(orderKey);

    if(obj1 == null && obj2 == null){
        return 0;
    }
    if (obj1 == null) {
        if(oType < 0){
            return -oType;
        }
        return oType;
    }
    if (obj2 == null) {
        if(oType < 0){
            return oType;
        }
        return -oType;
    }

    if(obj1 instanceof Date && obj2 instanceof Date){
        //日期排序
        Date date1 = (Date)obj1;
        Date date2 = (Date)obj2;
        return longCompare(oType, date1.getTime(), date2.getTime(), twoOrder, twoType,o1, o2);
    }else if(obj1 instanceof String && obj2 instanceof String){
        //字符串排序
        String str1 = obj1.toString();
        String str2 = obj2.toString();

        if(str1.compareTo(str2) < 0){
            return -oType;
        }else if(str1.compareTo(str2) == 0){
            return 0;
        }else if(str1.compareTo(str2) > 0){
            return oType;
        }
    }else if((obj1 instanceof Double || obj1 instanceof Float) && (obj2 instanceof Double || obj2 instanceof Float)){
        //浮点型排序
        return doubleCompare(oType, obj1, obj2, twoOrder, twoType,o1, o2);
    }else if((obj1 instanceof Long || obj1 instanceof Integer || obj1 instanceof Short || obj1 instanceof Byte) && 
             (obj2 instanceof Long || obj2 instanceof Integer || obj2 instanceof Short || obj2 instanceof Byte)){
        //整数型排序
        return longCompare(oType, obj1, obj2, twoOrder, twoType, o1, o2);
    }else if((obj1.getClass() != obj2.getClass()) && (obj1 instanceof Number && obj2 instanceof Number)){
        //这种情况可能是,既有整数又有浮点数
        return doubleCompare(oType, obj1, obj2, twoOrder, twoType,o1, o2);
    }
    return 0;
}

/**
 * 整形比较大小
 * @param oType
 * @param obj1
 * @param obj2
 * @param twoOrder
 * @param twoType
 * @return
 * @author yutao
 * @param o2 
 * @param o1 
 * @date 2018年5月24日下午3:09:18
 */
private static int longCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType, 
                               Map<String, Object> o1, Map<String, Object> o2) {
    long d1 = Long.parseLong(obj1.toString());
    long d2 = Long.parseLong(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){

        if(twoOrder != null && twoType != null){
            //相等就使用第二字段排序
            return commonOrder(twoOrder, twoType, null, null, o1, o2);
        }
        //相同的是否进行交互
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

/**
 * 浮点型比较大小
 * @param oType
 * @param obj1
 * @param obj2
 * @return
 * @author yutao
 * @param o2 
 * @param o1 
 * @date 2018年5月24日下午3:09:41
 */
private static int doubleCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType, 
                                 Map<String, Object> o1, Map<String, Object> o2) {
    double d1 = Double.parseDouble(obj1.toString());
    double d2 = Double.parseDouble(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        if(twoOrder != null && twoType != null){

            //相等就使用第二字段排序
            return commonOrder(twoOrder, twoType, null, null, o1, o2);
        }
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013066244/article/details/80169782