List的多维度排序案例演示~
来源:互联网 发布:读电子书软件 编辑:程序博客网 时间:2024/05/20 18:19
关于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; } }}
使用方法:
@Autowiredprivate SeriesDiagramEntityService seriesDiagramEntityService;@org.junit.Testpublic 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; } };}
这里排序规则比较多, 大概就是这样。
阅读全文
1 0
- List的多维度排序案例演示~
- 对List进行多维度排序
- Set、Map、list的排序,应用及案例
- PHP多维数组的排序
- 多维数组排序的算法
- 多维数组、数组的排序
- python 多维数组的排序
- php多维数组的排序
- javascript多维数组的排序
- python 多维数组的排序
- 演示FileInputStream案例演示
- 演示 FileOutputStream案例演示
- 利用List构造多维数组的误区
- numpy合并多维矩阵、list的扩展
- 多维度工作的数据设计到使用案例教程,采用OneNote、MindManager 等
- 案例:演示TCP传输过程的实现
- 实现图片的拷贝案例演示
- 真正的Javascript多维数组排序
- 从_NSA_攻击库到《Android_绿色应用公约》_国内移动开发环境安全性如何?
- Linux FTP服务器的搭建
- Windows ID事件及解释(XP、2000、2003)【转】
- 大数据、云计算系统顶级架构师课程学习路线图
- Mac浏览器 Silverlight 将未被识别或不断提示您安装问题处理
- List的多维度排序案例演示~
- 前端开发之布局和定位
- 4.客户端端接入文档
- 使用Spark SQL 探索“全国失信人数据”
- MYSQL设置编码
- 阻塞IO和非阻塞IO的区别(转载)
- mysql远程无法连接数据库的问题
- 二分查找
- JFinal -spring整合的代码