zoukankan      html  css  js  c++  java
  • List的多维度排序案例演示~

    文章也已同步到我的csdn:http://blog.csdn.net/u012881584/article/details/72377510

    关于List的多维度排序。

    日常工作中有很多关于list的排序功能, 看到公司封装的一个比较好的工具类, 这里拿来记录学习下。

    public class SortBuilder<T> {
    
        // Never make these public
        static final int LEFT_IS_GREATER = 1;
        static final int RIGHT_IS_GREATER = -1;
        private static final Logger log = LoggerFactory.getLogger(SortBuilder.class);
        private List<SortFiled<T>> sortFileds = Lists.newLinkedList();
        private Map<String, Method> propertyMethodMap = null;
        private boolean nullsFirst;
        private boolean nullsLast;
        private boolean zerosFirst;
        private boolean zerosLast;
        private boolean natural;
        private Direction naturalDirection;
    
        private SortBuilder() {
    
        }
    
        public static <C> SortBuilder<C> newBuilder(Class clazz) {
            SortBuilder<C> sortBuilder = new SortBuilder<>();
            PropertyDescriptor[] propertyDescriptor = BeanUtils.getPropertyDescriptors(clazz);
            Map<String, Method> propertyMethodMap = new HashMap<>();
            for (PropertyDescriptor pd : propertyDescriptor) {
                String key = pd.getName();
                Method value = pd.getReadMethod();
                propertyMethodMap.put(key, value);
            }
            sortBuilder.propertyMethodMap = propertyMethodMap;
            return sortBuilder;
        }
    
        /**
         * null 排序到最前面
         */
        public SortBuilder<T> nullsFirst() {
            nullsFirst = true;
            nullsLast = false;
            return this;
        }
    
        /**
         * null 排序到最后面
         */
        public SortBuilder<T> nullsLast() {
            nullsFirst = false;
            nullsLast = true;
            return this;
        }
    
        /**
         * 0 排序到最后面
         */
        public SortBuilder<T> zerosLast() {
            zerosFirst = false;
            zerosLast = true;
            return this;
        }
    
        /**
         * 0 排序到最前面
         */
        public SortBuilder<T> zerosFirst() {
            zerosFirst = true;
            zerosLast = false;
            return this;
        }
    
        /**
         * 自然排序 {1,5,3,2,4} = {1,2,3,4,5}
         */
        public SortBuilder<T> natural() {
            natural = true;
            return this;
        }
    
        /**
         * 自然排序 {1,5,3,2,4} = {1,2,3,4,5}
         */
        public SortBuilder<T> natural(Direction direction) {
            natural = true;
            naturalDirection = direction;
            return this;
        }
    
        public SortBuilder<T> clear() {
            sortFileds.clear();
            return this;
        }
    
        /**
         * 增加一个降序
         *
         * @param fieldName 属性
         */
        public SortBuilder<T> addDesc(String fieldName) {
            addFieldMethod(fieldName, Direction.DESC);
            return this;
        }
    
        /**
         * 增加一个自定义排序
         *
         * @param comparator 自定义比较器
         */
        public SortBuilder<T> addCustom(Comparator<T> comparator) {
            sortFileds.add(SortFiled.builder(Direction.CUSTOM, null, comparator));
            return this;
        }
    
    
        /**
         * 增加一个升序
         *
         * @param fieldName 属性
         */
        public SortBuilder<T> addAsc(String fieldName) {
            addFieldMethod(fieldName, Direction.ASC);
            return this;
        }
    
        /**
         * 增加一个字段排序模式
         *
         * @param fieldName 属性
         * @param direction 排序方式
         */
        private SortBuilder<T> addFieldMethod(String fieldName, Direction direction) {
            Method method = propertyMethodMap.get(fieldName);
            if (method == null) {
                log.error("NoSuchMethodException field:{}", fieldName);
            } else {
                sortFileds.add(SortFiled.<T>builder(direction, method, null));
            }
            return this;
        }
    
        public SortBuilder<T> sortList(List<T> list) {
            Collections.sort(list, buildComparator());
            return this;
        }
    
        private Comparator<T> buildComparator() {
            return new Comparator<T>() {
                public int compare(T o1, T o2) {
                    int flag = 0;
                    if (sortFileds.size() == 0 && natural) {
                        flag = compareNatural(o1, o2, naturalDirection);
                    } else {
                        for (SortFiled<T> sortFiled : sortFileds) {
                            Method method = sortFiled.getMethod();
                            Direction direction = sortFiled.getDirection();
                            if (direction == Direction.CUSTOM) {
                                flag = sortFiled.getComparator().compare(o1, o2);
                            } else {
                                flag = this.compare(method, o1, o2, direction);
                            }
                            if (flag != 0) {
                                break;
                            }
                        }
                    }
                    return flag;
                }
    
                private int compare(Method method, T left, T right, Direction direction) {
                    int flag = 0;
                    try {
                        Object leftVal = method.invoke(left);
                        Object rightVal = method.invoke(right);
                        Class returnType = method.getReturnType();
                        if (nullsFirst) {
                            flag = compareNulls(returnType, leftVal, rightVal, false, direction);
                        } else if (nullsLast) {
                            flag = compareNulls(returnType, rightVal, leftVal, true, direction);
                        } else {
                            flag = compare(returnType, leftVal, rightVal, direction);
                        }
                    } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    return flag;
                }
    
                private int compareNatural(Object leftVal, Object rightVal, Direction direction) {
                    int flag;
                    if (nullsFirst) {
                        flag = compareNulls(leftVal, rightVal, false, direction);
                    } else if (nullsLast) {
                        flag = compareNulls(rightVal, leftVal, true, direction);
                    } else {
                        flag = compare(leftVal.getClass(), leftVal, rightVal, direction);
                    }
                    return flag;
                }
    
                private int compareNulls(Object leftVal, Object rightVal, boolean reverse, Direction direction) {
                    return compareNulls(leftVal == null ? null : leftVal.getClass(), leftVal, rightVal, reverse, direction);
                }
    
                private int compareNulls(Class returnType, Object leftVal, Object rightVal, boolean reverse,
                                         Direction direction) {
                    if (leftVal == rightVal) {
                        return 0;
                    } else if (leftVal == null) {
                        return RIGHT_IS_GREATER;
                    } else if (rightVal == null) {
                        return LEFT_IS_GREATER;
                    } else {
                        return reverse ? compare(returnType, rightVal, leftVal, direction) : compare(returnType, leftVal,
                                rightVal, direction);
                    }
                }
    
                private int compareZeros(BigDecimal leftNumber, BigDecimal rightNumber, boolean reverse, Direction direction) {
                    if (leftNumber.compareTo(rightNumber) == 0) {
                        return 0;
                    } else if (leftNumber.compareTo(BigDecimal.valueOf(0)) == 0) {
                        return RIGHT_IS_GREATER;
                    } else if (rightNumber.compareTo(BigDecimal.valueOf(0)) == 0) {
                        return LEFT_IS_GREATER;
                    } else {
                        return reverse ? compareNumber(rightNumber, leftNumber, direction) : compareNumber(leftNumber,
                                rightNumber, direction);
                    }
                }
    
                private int compareNumber(BigDecimal leftNumber, BigDecimal rightNumber, Direction direction) {
                    if (leftNumber.compareTo(rightNumber) == 0) {
                        return 0;
                    } else {
                        return direction == null || direction == Direction.ASC ? leftNumber.compareTo(rightNumber)
                                : rightNumber.compareTo(leftNumber);
                    }
                }
    
                private int compare(Class returnType, Object leftVal, Object rightVal, Direction direction) {
                    int flag;
                    if (Number.class.isAssignableFrom(returnType) || returnType == int.class || returnType == long.class
                            || returnType == double.class || returnType == float.class) {
                        BigDecimal leftNumber = BigDecimal.valueOf(Double.valueOf(leftVal.toString()));
                        BigDecimal rightNumber = BigDecimal.valueOf(Double.valueOf(rightVal.toString()));
                        if (zerosFirst) {
                            flag = compareZeros(leftNumber, rightNumber, false, direction);
                        } else if (zerosLast) {
                            flag = compareZeros(rightNumber, leftNumber, true, direction);
                        } else {
                            flag = compareNumber(leftNumber, rightNumber, direction);
                        }
                    } else {
                        String methodReturn1 = leftVal.toString();
                        String methodReturn2 = rightVal.toString();
                        if (direction == null || direction == Direction.ASC) {
                            flag = methodReturn1.compareTo(methodReturn2);
                        } else {
                            flag = methodReturn2.compareTo(methodReturn1);
                        }
                    }
                    return flag;
                }
            };
        }
    
        /**
         * 排序方式:
         * <p/>
         * ASC:升序,DESC:降序
         */
        public enum Direction {
            ASC, DESC, CUSTOM
        }
    
        static class SortFiled<T> {
            private Method method;
            private Direction direction;
            private Comparator<T> comparator;
    
    
            SortFiled(Direction direction, Method method, Comparator<T> comparator) {
                this.method = method;
                this.direction = direction;
                this.comparator = comparator;
            }
    
            @SuppressWarnings("unchecked")
            public static <T> SortFiled<T> builder(Direction direction, Method method, Comparator<T> comparator) {
                return new SortFiled(direction, method, comparator);
            }
    
            public Method getMethod() {
                return method;
            }
    
            public void setMethod(Method method) {
                this.method = method;
            }
    
            public Direction getDirection() {
                return direction;
            }
    
            public void setDirection(Direction direction) {
                this.direction = direction;
            }
    
            public Comparator<T> getComparator() {
                return comparator;
            }
    
            public void setComparator(Comparator<T> comparator) {
                this.comparator = comparator;
            }
        }
    }
    

    使用方法:

    @Autowired
    private SeriesDiagramEntityService seriesDiagramEntityService;
    @org.junit.Test
    public void testSortBuilder() throws Exception{
        List<SeriesDiagramEntity> list = seriesDiagramEntityService.findAll(SeriesDiagramEntity.Fields.status.eq(CommonConstants.DataStatus.PUBLISH).limit(1000));
        SortBuilder.<SeriesDiagramEntity>newBuilder(SeriesDiagramEntity.class).addAsc("source").addAsc("displayOrder").addDesc("status").sortList(list);
    }
    

    使用起来很简单,我们这里写了个unit test来演示。 原理就是直接使用JavaBean中的属性进行asc或者desc的排序展示。

    下面来看看它是具体怎么运行的:

    • 首先获取到实体类的属性, 然后添加到propertyMethodMap中。
    PropertyDescriptor[] propertyDescriptor = BeanUtils.getPropertyDescriptors(clazz);
    

    获取实体类的属性

    • 然后是将用户自定义的排序字段加入到sortFileds中去:
    
    /**
     * 增加一个升序
     *
     * @param fieldName 属性
     */
    public SortBuilder<T> addAsc(String fieldName) {
        addFieldMethod(fieldName, Direction.ASC);
        return this;
    }
    
    
    /**
     * 增加一个字段排序模式
     *
     * @param fieldName 属性
     * @param direction 排序方式
     */
    private SortBuilder<T> addFieldMethod(String fieldName, Direction direction) {
        Method method = propertyMethodMap.get(fieldName);
        if (method == null) {
            log.error("NoSuchMethodException field:{}", fieldName);
        } else {
            sortFileds.add(SortFiled.<T>builder(direction, method, null));
        }
        return this;
    }
    

    添加排序字段

    • 进行排序
    public SortBuilder<T> sortList(List<T> list) {
        Collections.sort(list, buildComparator());
        return this;
    }
    
    private Comparator<T> buildComparator() {
        return new Comparator<T>() {
            public int compare(T o1, T o2) {
                int flag = 0;
                if (sortFileds.size() == 0 && natural) {
                    flag = compareNatural(o1, o2, naturalDirection);
                } else {
                    for (SortFiled<T> sortFiled : sortFileds) {
                        Method method = sortFiled.getMethod();
                        Direction direction = sortFiled.getDirection();
                        if (direction == Direction.CUSTOM) {
                            flag = sortFiled.getComparator().compare(o1, o2);
                        } else {
                            flag = this.compare(method, o1, o2, direction);
                        }
                        if (flag != 0) {
                            break;
                        }
                    }
                }
                return flag;
            }
    
            private int compare(Method method, T left, T right, Direction direction) {
                int flag = 0;
                try {
                    Object leftVal = method.invoke(left);
                    Object rightVal = method.invoke(right);
                    Class returnType = method.getReturnType();
                    if (nullsFirst) {
                        flag = compareNulls(returnType, leftVal, rightVal, false, direction);
                    } else if (nullsLast) {
                        flag = compareNulls(returnType, rightVal, leftVal, true, direction);
                    } else {
                        flag = compare(returnType, leftVal, rightVal, direction);
                    }
                } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return flag;
            }
    
            private int compareNatural(Object leftVal, Object rightVal, Direction direction) {
                int flag;
                if (nullsFirst) {
                    flag = compareNulls(leftVal, rightVal, false, direction);
                } else if (nullsLast) {
                    flag = compareNulls(rightVal, leftVal, true, direction);
                } else {
                    flag = compare(leftVal.getClass(), leftVal, rightVal, direction);
                }
                return flag;
            }
    
            private int compareNulls(Object leftVal, Object rightVal, boolean reverse, Direction direction) {
                return compareNulls(leftVal == null ? null : leftVal.getClass(), leftVal, rightVal, reverse, direction);
            }
    
            private int compareNulls(Class returnType, Object leftVal, Object rightVal, boolean reverse,
                                     Direction direction) {
                if (leftVal == rightVal) {
                    return 0;
                } else if (leftVal == null) {
                    return RIGHT_IS_GREATER;
                } else if (rightVal == null) {
                    return LEFT_IS_GREATER;
                } else {
                    return reverse ? compare(returnType, rightVal, leftVal, direction) : compare(returnType, leftVal,
                            rightVal, direction);
                }
            }
    
            private int compareZeros(BigDecimal leftNumber, BigDecimal rightNumber, boolean reverse, Direction direction) {
                if (leftNumber.compareTo(rightNumber) == 0) {
                    return 0;
                } else if (leftNumber.compareTo(BigDecimal.valueOf(0)) == 0) {
                    return RIGHT_IS_GREATER;
                } else if (rightNumber.compareTo(BigDecimal.valueOf(0)) == 0) {
                    return LEFT_IS_GREATER;
                } else {
                    return reverse ? compareNumber(rightNumber, leftNumber, direction) : compareNumber(leftNumber,
                            rightNumber, direction);
                }
            }
    
            private int compareNumber(BigDecimal leftNumber, BigDecimal rightNumber, Direction direction) {
                if (leftNumber.compareTo(rightNumber) == 0) {
                    return 0;
                } else {
                    return direction == null || direction == Direction.ASC ? leftNumber.compareTo(rightNumber)
                            : rightNumber.compareTo(leftNumber);
                }
            }
    
            private int compare(Class returnType, Object leftVal, Object rightVal, Direction direction) {
                int flag;
                if (Number.class.isAssignableFrom(returnType) || returnType == int.class || returnType == long.class
                        || returnType == double.class || returnType == float.class) {
                    BigDecimal leftNumber = BigDecimal.valueOf(Double.valueOf(leftVal.toString()));
                    BigDecimal rightNumber = BigDecimal.valueOf(Double.valueOf(rightVal.toString()));
                    if (zerosFirst) {
                        flag = compareZeros(leftNumber, rightNumber, false, direction);
                    } else if (zerosLast) {
                        flag = compareZeros(rightNumber, leftNumber, true, direction);
                    } else {
                        flag = compareNumber(leftNumber, rightNumber, direction);
                    }
                } else {
                    String methodReturn1 = leftVal.toString();
                    String methodReturn2 = rightVal.toString();
                    if (direction == null || direction == Direction.ASC) {
                        flag = methodReturn1.compareTo(methodReturn2);
                    } else {
                        flag = methodReturn2.compareTo(methodReturn1);
                    }
                }
                return flag;
            }
        };
    }
    

    这里排序规则比较多, 大概就是这样。

  • 相关阅读:
    目标检测——从RCNN到Faster RCNN 串烧
    论文阅读:SSD: Single Shot MultiBox Detector
    在stm32上使用Arduino IDE(神舟I号为例)
    低功耗STM32F411开发板(原理图+PCB源文件+官方例程+驱动等)
    arduino的IDE开发stm32的板子
    AltiumDesigner14.3.X系列软件安装及破解过程
    arduino-star-otto
    怎样成为一个高手
    我的ubuntu10.04网络设置(VirtualBox)
    ubuntu11.04下安装TCL及TK
  • 原文地址:https://www.cnblogs.com/wang-meng/p/6867219.html
Copyright © 2011-2022 走看看