前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >List的多维度排序案例演示~

List的多维度排序案例演示~

作者头像
一枝花算不算浪漫
发布2018-05-18 14:45:18
9630
发布2018-05-18 14:45:18
举报

关于List的多维度排序

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

代码语言:javascript
复制
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;
        }
    }
}

使用方法:

代码语言:javascript
复制
@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中去:
代码语言:javascript
复制
/**
 * 增加一个升序
 *
 * @param fieldName 属性
 */
public SortBuilder<T> addAsc(String fieldName) {
    addFieldMethod(fieldName, Direction.ASC);
    return this;
}
代码语言:javascript
复制
/**
 * 增加一个字段排序模式
 *
 * @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;
}
添加排序字段
添加排序字段
  • 进行排序
代码语言:javascript
复制
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;
        }
    };
}

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-05-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于List的多维度排序
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档